{"version":3,"sources":["../../node_modules/ua-parser-js/src/ua-parser.js","../../node_modules/lodash-es/_freeGlobal.js","../../node_modules/lodash-es/_root.js","../../node_modules/lodash-es/_Symbol.js","../../node_modules/lodash-es/_getRawTag.js","../../node_modules/lodash-es/_objectToString.js","../../node_modules/lodash-es/_baseGetTag.js","../../node_modules/lodash-es/isObjectLike.js","../../node_modules/lodash-es/isSymbol.js","../../node_modules/lodash-es/_trimmedEndIndex.js","../../node_modules/lodash-es/_baseTrim.js","../../node_modules/lodash-es/isObject.js","../../node_modules/lodash-es/toNumber.js","../../node_modules/lodash-es/_baseClamp.js","../../node_modules/lodash-es/clamp.js","../../node_modules/@motionone/utils/dist/array.es.js","../../node_modules/@motionone/utils/dist/clamp.es.js","../../node_modules/@motionone/utils/dist/defaults.es.js","../../node_modules/@motionone/utils/dist/is-number.es.js","../../node_modules/@motionone/utils/dist/is-easing-list.es.js","../../node_modules/@motionone/utils/dist/wrap.es.js","../../node_modules/@motionone/utils/dist/easing.es.js","../../node_modules/@motionone/utils/dist/mix.es.js","../../node_modules/@motionone/utils/dist/noop.es.js","../../node_modules/@motionone/utils/dist/progress.es.js","../../node_modules/@motionone/utils/dist/offset.es.js","../../node_modules/@motionone/utils/dist/interpolate.es.js","../../node_modules/@motionone/utils/dist/is-cubic-bezier.es.js","../../node_modules/@motionone/utils/dist/is-easing-generator.es.js","../../node_modules/@motionone/utils/dist/is-function.es.js","../../node_modules/@motionone/utils/dist/is-string.es.js","../../node_modules/@motionone/utils/dist/time.es.js","../../node_modules/@motionone/easing/dist/cubic-bezier.es.js","../../node_modules/@motionone/easing/dist/steps.es.js","../../node_modules/@motionone/animation/dist/utils/easing.es.js","../../node_modules/@motionone/animation/dist/Animation.es.js","../../node_modules/hey-listen/dist/hey-listen.es.js","../../node_modules/@motionone/types/dist/MotionValue.es.js","../../node_modules/@motionone/dom/dist/animate/data.es.js","../../node_modules/@motionone/dom/dist/animate/utils/transforms.es.js","../../node_modules/@motionone/dom/dist/animate/utils/css-var.es.js","../../node_modules/@motionone/dom/dist/animate/utils/feature-detection.es.js","../../node_modules/@motionone/dom/dist/animate/utils/easing.es.js","../../node_modules/@motionone/dom/dist/animate/utils/keyframes.es.js","../../node_modules/@motionone/dom/dist/animate/utils/get-style-name.es.js","../../node_modules/@motionone/dom/dist/animate/style.es.js","../../node_modules/@motionone/dom/dist/animate/utils/stop-animation.es.js","../../node_modules/@motionone/dom/dist/animate/utils/get-unit.es.js","../../node_modules/@motionone/dom/dist/animate/animate-style.es.js","../../node_modules/@motionone/dom/dist/animate/utils/options.es.js","../../node_modules/@motionone/dom/dist/utils/resolve-elements.es.js","../../node_modules/@motionone/dom/dist/animate/utils/controls.es.js","../../node_modules/@motionone/dom/dist/utils/stagger.es.js","../../node_modules/@motionone/dom/dist/animate/create-animate.es.js","../../node_modules/@motionone/dom/dist/animate/index.es.js","../../node_modules/motion/dist/animate.es.js","../../preloader/Preloader.ts","../../assets/src/BuildConfig.ts","../../assets/src/utils/collection/get-object-keys.ts","../../assets/src/utils/device/is-desktop.ts","../../assets/src/utils/local-storage-utils.ts","../../assets/src/utils/UrlParams.ts","../../assets/src/utils/platform/platform.ts","../../assets/src/utils/Result.ts","../../assets/src/utils/deferred.ts","../../assets/src/utils/net/load-script.ts","../../preloader/platform/IPlatformPreloader.ts","../../preloader/platform/CrazyGamesPlatformPreloader.ts","../../preloader/platform/FbPlatformPreloader.ts","../../assets/src/utils/assert-never.ts","../../preloader/platform/VkPlatformPreloader.ts","../../preloader/platform/YaPlatformPreloader.ts"],"sourcesContent":["/////////////////////////////////////////////////////////////////////////////////\n/* UAParser.js v1.0.37\n Copyright © 2012-2021 Faisal Salman \n MIT License *//*\n Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.\n Supports browser & node.js environment. \n Demo : https://faisalman.github.io/ua-parser-js\n Source : https://github.com/faisalman/ua-parser-js */\n/////////////////////////////////////////////////////////////////////////////////\n\n(function (window, undefined) {\n\n 'use strict';\n\n //////////////\n // Constants\n /////////////\n\n\n var LIBVERSION = '1.0.37',\n EMPTY = '',\n UNKNOWN = '?',\n FUNC_TYPE = 'function',\n UNDEF_TYPE = 'undefined',\n OBJ_TYPE = 'object',\n STR_TYPE = 'string',\n MAJOR = 'major',\n MODEL = 'model',\n NAME = 'name',\n TYPE = 'type',\n VENDOR = 'vendor',\n VERSION = 'version',\n ARCHITECTURE= 'architecture',\n CONSOLE = 'console',\n MOBILE = 'mobile',\n TABLET = 'tablet',\n SMARTTV = 'smarttv',\n WEARABLE = 'wearable',\n EMBEDDED = 'embedded',\n UA_MAX_LENGTH = 500;\n\n var AMAZON = 'Amazon',\n APPLE = 'Apple',\n ASUS = 'ASUS',\n BLACKBERRY = 'BlackBerry',\n BROWSER = 'Browser',\n CHROME = 'Chrome',\n EDGE = 'Edge',\n FIREFOX = 'Firefox',\n GOOGLE = 'Google',\n HUAWEI = 'Huawei',\n LG = 'LG',\n MICROSOFT = 'Microsoft',\n MOTOROLA = 'Motorola',\n OPERA = 'Opera',\n SAMSUNG = 'Samsung',\n SHARP = 'Sharp',\n SONY = 'Sony',\n XIAOMI = 'Xiaomi',\n ZEBRA = 'Zebra',\n FACEBOOK = 'Facebook',\n CHROMIUM_OS = 'Chromium OS',\n MAC_OS = 'Mac OS';\n\n ///////////\n // Helper\n //////////\n\n var extend = function (regexes, extensions) {\n var mergedRegexes = {};\n for (var i in regexes) {\n if (extensions[i] && extensions[i].length % 2 === 0) {\n mergedRegexes[i] = extensions[i].concat(regexes[i]);\n } else {\n mergedRegexes[i] = regexes[i];\n }\n }\n return mergedRegexes;\n },\n enumerize = function (arr) {\n var enums = {};\n for (var i=0; i 0) {\n if (q.length === 2) {\n if (typeof q[1] == FUNC_TYPE) {\n // assign modified match\n this[q[0]] = q[1].call(this, match);\n } else {\n // assign given value, ignore regex match\n this[q[0]] = q[1];\n }\n } else if (q.length === 3) {\n // check whether function or regex\n if (typeof q[1] === FUNC_TYPE && !(q[1].exec && q[1].test)) {\n // call function (usually string mapper)\n this[q[0]] = match ? q[1].call(this, match, q[2]) : undefined;\n } else {\n // sanitize match using given regex\n this[q[0]] = match ? match.replace(q[1], q[2]) : undefined;\n }\n } else if (q.length === 4) {\n this[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined;\n }\n } else {\n this[q] = match ? match : undefined;\n }\n }\n }\n }\n i += 2;\n }\n },\n\n strMapper = function (str, map) {\n\n for (var i in map) {\n // check if current value is array\n if (typeof map[i] === OBJ_TYPE && map[i].length > 0) {\n for (var j = 0; j < map[i].length; j++) {\n if (has(map[i][j], str)) {\n return (i === UNKNOWN) ? undefined : i;\n }\n }\n } else if (has(map[i], str)) {\n return (i === UNKNOWN) ? undefined : i;\n }\n }\n return str;\n };\n\n ///////////////\n // String map\n //////////////\n\n // Safari < 3.0\n var oldSafariMap = {\n '1.0' : '/8',\n '1.2' : '/1',\n '1.3' : '/3',\n '2.0' : '/412',\n '2.0.2' : '/416',\n '2.0.3' : '/417',\n '2.0.4' : '/419',\n '?' : '/'\n },\n windowsVersionMap = {\n 'ME' : '4.90',\n 'NT 3.11' : 'NT3.51',\n 'NT 4.0' : 'NT4.0',\n '2000' : 'NT 5.0',\n 'XP' : ['NT 5.1', 'NT 5.2'],\n 'Vista' : 'NT 6.0',\n '7' : 'NT 6.1',\n '8' : 'NT 6.2',\n '8.1' : 'NT 6.3',\n '10' : ['NT 6.4', 'NT 10.0'],\n 'RT' : 'ARM'\n };\n\n //////////////\n // Regex map\n /////////////\n\n var regexes = {\n\n browser : [[\n\n /\\b(?:crmo|crios)\\/([\\w\\.]+)/i // Chrome for Android/iOS\n ], [VERSION, [NAME, 'Chrome']], [\n /edg(?:e|ios|a)?\\/([\\w\\.]+)/i // Microsoft Edge\n ], [VERSION, [NAME, 'Edge']], [\n\n // Presto based\n /(opera mini)\\/([-\\w\\.]+)/i, // Opera Mini\n /(opera [mobiletab]{3,6})\\b.+version\\/([-\\w\\.]+)/i, // Opera Mobi/Tablet\n /(opera)(?:.+version\\/|[\\/ ]+)([\\w\\.]+)/i // Opera\n ], [NAME, VERSION], [\n /opios[\\/ ]+([\\w\\.]+)/i // Opera mini on iphone >= 8.0\n ], [VERSION, [NAME, OPERA+' Mini']], [\n /\\bopr\\/([\\w\\.]+)/i // Opera Webkit\n ], [VERSION, [NAME, OPERA]], [\n\n // Mixed\n /\\bb[ai]*d(?:uhd|[ub]*[aekoprswx]{5,6})[\\/ ]?([\\w\\.]+)/i // Baidu\n ], [VERSION, [NAME, 'Baidu']], [\n /(kindle)\\/([\\w\\.]+)/i, // Kindle\n /(lunascape|maxthon|netfront|jasmine|blazer)[\\/ ]?([\\w\\.]*)/i, // Lunascape/Maxthon/Netfront/Jasmine/Blazer\n // Trident based\n /(avant|iemobile|slim)\\s?(?:browser)?[\\/ ]?([\\w\\.]*)/i, // Avant/IEMobile/SlimBrowser\n /(?:ms|\\()(ie) ([\\w\\.]+)/i, // Internet Explorer\n\n // Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon\n /(flock|rockmelt|midori|epiphany|silk|skyfire|bolt|iron|vivaldi|iridium|phantomjs|bowser|quark|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|qq|duckduckgo)\\/([-\\w\\.]+)/i,\n // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ, aka ShouQ\n /(heytap|ovi)browser\\/([\\d\\.]+)/i, // Heytap/Ovi\n /(weibo)__([\\d\\.]+)/i // Weibo\n ], [NAME, VERSION], [\n /(?:\\buc? ?browser|(?:juc.+)ucweb)[\\/ ]?([\\w\\.]+)/i // UCBrowser\n ], [VERSION, [NAME, 'UC'+BROWSER]], [\n /microm.+\\bqbcore\\/([\\w\\.]+)/i, // WeChat Desktop for Windows Built-in Browser\n /\\bqbcore\\/([\\w\\.]+).+microm/i,\n /micromessenger\\/([\\w\\.]+)/i // WeChat\n ], [VERSION, [NAME, 'WeChat']], [\n /konqueror\\/([\\w\\.]+)/i // Konqueror\n ], [VERSION, [NAME, 'Konqueror']], [\n /trident.+rv[: ]([\\w\\.]{1,9})\\b.+like gecko/i // IE11\n ], [VERSION, [NAME, 'IE']], [\n /ya(?:search)?browser\\/([\\w\\.]+)/i // Yandex\n ], [VERSION, [NAME, 'Yandex']], [\n /slbrowser\\/([\\w\\.]+)/i // Smart Lenovo Browser\n ], [VERSION, [NAME, 'Smart Lenovo '+BROWSER]], [\n /(avast|avg)\\/([\\w\\.]+)/i // Avast/AVG Secure Browser\n ], [[NAME, /(.+)/, '$1 Secure '+BROWSER], VERSION], [\n /\\bfocus\\/([\\w\\.]+)/i // Firefox Focus\n ], [VERSION, [NAME, FIREFOX+' Focus']], [\n /\\bopt\\/([\\w\\.]+)/i // Opera Touch\n ], [VERSION, [NAME, OPERA+' Touch']], [\n /coc_coc\\w+\\/([\\w\\.]+)/i // Coc Coc Browser\n ], [VERSION, [NAME, 'Coc Coc']], [\n /dolfin\\/([\\w\\.]+)/i // Dolphin\n ], [VERSION, [NAME, 'Dolphin']], [\n /coast\\/([\\w\\.]+)/i // Opera Coast\n ], [VERSION, [NAME, OPERA+' Coast']], [\n /miuibrowser\\/([\\w\\.]+)/i // MIUI Browser\n ], [VERSION, [NAME, 'MIUI '+BROWSER]], [\n /fxios\\/([-\\w\\.]+)/i // Firefox for iOS\n ], [VERSION, [NAME, FIREFOX]], [\n /\\bqihu|(qi?ho?o?|360)browser/i // 360\n ], [[NAME, '360 ' + BROWSER]], [\n /(oculus|sailfish|huawei|vivo)browser\\/([\\w\\.]+)/i\n ], [[NAME, /(.+)/, '$1 ' + BROWSER], VERSION], [ // Oculus/Sailfish/HuaweiBrowser/VivoBrowser\n /samsungbrowser\\/([\\w\\.]+)/i // Samsung Internet\n ], [VERSION, [NAME, SAMSUNG + ' Internet']], [\n /(comodo_dragon)\\/([\\w\\.]+)/i // Comodo Dragon\n ], [[NAME, /_/g, ' '], VERSION], [\n /metasr[\\/ ]?([\\d\\.]+)/i // Sogou Explorer\n ], [VERSION, [NAME, 'Sogou Explorer']], [\n /(sogou)mo\\w+\\/([\\d\\.]+)/i // Sogou Mobile\n ], [[NAME, 'Sogou Mobile'], VERSION], [\n /(electron)\\/([\\w\\.]+) safari/i, // Electron-based App\n /(tesla)(?: qtcarbrowser|\\/(20\\d\\d\\.[-\\w\\.]+))/i, // Tesla\n /m?(qqbrowser|2345Explorer)[\\/ ]?([\\w\\.]+)/i // QQBrowser/2345 Browser\n ], [NAME, VERSION], [\n /(lbbrowser)/i, // LieBao Browser\n /\\[(linkedin)app\\]/i // LinkedIn App for iOS & Android\n ], [NAME], [\n\n // WebView\n /((?:fban\\/fbios|fb_iab\\/fb4a)(?!.+fbav)|;fbav\\/([\\w\\.]+);)/i // Facebook App for iOS & Android\n ], [[NAME, FACEBOOK], VERSION], [\n /(Klarna)\\/([\\w\\.]+)/i, // Klarna Shopping Browser for iOS & Android\n /(kakao(?:talk|story))[\\/ ]([\\w\\.]+)/i, // Kakao App\n /(naver)\\(.*?(\\d+\\.[\\w\\.]+).*\\)/i, // Naver InApp\n /safari (line)\\/([\\w\\.]+)/i, // Line App for iOS\n /\\b(line)\\/([\\w\\.]+)\\/iab/i, // Line App for Android\n /(alipay)client\\/([\\w\\.]+)/i, // Alipay\n /(chromium|instagram|snapchat)[\\/ ]([-\\w\\.]+)/i // Chromium/Instagram/Snapchat\n ], [NAME, VERSION], [\n /\\bgsa\\/([\\w\\.]+) .*safari\\//i // Google Search Appliance on iOS\n ], [VERSION, [NAME, 'GSA']], [\n /musical_ly(?:.+app_?version\\/|_)([\\w\\.]+)/i // TikTok\n ], [VERSION, [NAME, 'TikTok']], [\n\n /headlesschrome(?:\\/([\\w\\.]+)| )/i // Chrome Headless\n ], [VERSION, [NAME, CHROME+' Headless']], [\n\n / wv\\).+(chrome)\\/([\\w\\.]+)/i // Chrome WebView\n ], [[NAME, CHROME+' WebView'], VERSION], [\n\n /droid.+ version\\/([\\w\\.]+)\\b.+(?:mobile safari|safari)/i // Android Browser\n ], [VERSION, [NAME, 'Android '+BROWSER]], [\n\n /(chrome|omniweb|arora|[tizenoka]{5} ?browser)\\/v?([\\w\\.]+)/i // Chrome/OmniWeb/Arora/Tizen/Nokia\n ], [NAME, VERSION], [\n\n /version\\/([\\w\\.\\,]+) .*mobile\\/\\w+ (safari)/i // Mobile Safari\n ], [VERSION, [NAME, 'Mobile Safari']], [\n /version\\/([\\w(\\.|\\,)]+) .*(mobile ?safari|safari)/i // Safari & Safari Mobile\n ], [VERSION, NAME], [\n /webkit.+?(mobile ?safari|safari)(\\/[\\w\\.]+)/i // Safari < 3.0\n ], [NAME, [VERSION, strMapper, oldSafariMap]], [\n\n /(webkit|khtml)\\/([\\w\\.]+)/i\n ], [NAME, VERSION], [\n\n // Gecko based\n /(navigator|netscape\\d?)\\/([-\\w\\.]+)/i // Netscape\n ], [[NAME, 'Netscape'], VERSION], [\n /mobile vr; rv:([\\w\\.]+)\\).+firefox/i // Firefox Reality\n ], [VERSION, [NAME, FIREFOX+' Reality']], [\n /ekiohf.+(flow)\\/([\\w\\.]+)/i, // Flow\n /(swiftfox)/i, // Swiftfox\n /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror|klar)[\\/ ]?([\\w\\.\\+]+)/i,\n // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror/Klar\n /(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\\/([-\\w\\.]+)$/i,\n // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix\n /(firefox)\\/([\\w\\.]+)/i, // Other Firefox-based\n /(mozilla)\\/([\\w\\.]+) .+rv\\:.+gecko\\/\\d+/i, // Mozilla\n\n // Other\n /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|sleipnir|obigo|mosaic|(?:go|ice|up)[\\. ]?browser)[-\\/ ]?v?([\\w\\.]+)/i,\n // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Sleipnir/Obigo/Mosaic/Go/ICE/UP.Browser\n /(links) \\(([\\w\\.]+)/i, // Links\n /panasonic;(viera)/i // Panasonic Viera\n ], [NAME, VERSION], [\n \n /(cobalt)\\/([\\w\\.]+)/i // Cobalt\n ], [NAME, [VERSION, /master.|lts./, \"\"]]\n ],\n\n cpu : [[\n\n /(?:(amd|x(?:(?:86|64)[-_])?|wow|win)64)[;\\)]/i // AMD64 (x64)\n ], [[ARCHITECTURE, 'amd64']], [\n\n /(ia32(?=;))/i // IA32 (quicktime)\n ], [[ARCHITECTURE, lowerize]], [\n\n /((?:i[346]|x)86)[;\\)]/i // IA32 (x86)\n ], [[ARCHITECTURE, 'ia32']], [\n\n /\\b(aarch64|arm(v?8e?l?|_?64))\\b/i // ARM64\n ], [[ARCHITECTURE, 'arm64']], [\n\n /\\b(arm(?:v[67])?ht?n?[fl]p?)\\b/i // ARMHF\n ], [[ARCHITECTURE, 'armhf']], [\n\n // PocketPC mistakenly identified as PowerPC\n /windows (ce|mobile); ppc;/i\n ], [[ARCHITECTURE, 'arm']], [\n\n /((?:ppc|powerpc)(?:64)?)(?: mac|;|\\))/i // PowerPC\n ], [[ARCHITECTURE, /ower/, EMPTY, lowerize]], [\n\n /(sun4\\w)[;\\)]/i // SPARC\n ], [[ARCHITECTURE, 'sparc']], [\n\n /((?:avr32|ia64(?=;))|68k(?=\\))|\\barm(?=v(?:[1-7]|[5-7]1)l?|;|eabi)|(?=atmel )avr|(?:irix|mips|sparc)(?:64)?\\b|pa-risc)/i\n // IA64, 68K, ARM/64, AVR/32, IRIX/64, MIPS/64, SPARC/64, PA-RISC\n ], [[ARCHITECTURE, lowerize]]\n ],\n\n device : [[\n\n //////////////////////////\n // MOBILES & TABLETS\n /////////////////////////\n\n // Samsung\n /\\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\n ], [MODEL, [VENDOR, SAMSUNG], [TYPE, TABLET]], [\n /\\b((?:s[cgp]h|gt|sm)-\\w+|sc[g-]?[\\d]+a?|galaxy nexus)/i,\n /samsung[- ]([-\\w]+)/i,\n /sec-(sgh\\w+)/i\n ], [MODEL, [VENDOR, SAMSUNG], [TYPE, MOBILE]], [\n\n // Apple\n /(?:\\/|\\()(ip(?:hone|od)[\\w, ]*)(?:\\/|;)/i // iPod/iPhone\n ], [MODEL, [VENDOR, APPLE], [TYPE, MOBILE]], [\n /\\((ipad);[-\\w\\),; ]+apple/i, // iPad\n /applecoremedia\\/[\\w\\.]+ \\((ipad)/i,\n /\\b(ipad)\\d\\d?,\\d\\d?[;\\]].+ios/i\n ], [MODEL, [VENDOR, APPLE], [TYPE, TABLET]], [\n /(macintosh);/i\n ], [MODEL, [VENDOR, APPLE]], [\n\n // Sharp\n /\\b(sh-?[altvz]?\\d\\d[a-ekm]?)/i\n ], [MODEL, [VENDOR, SHARP], [TYPE, MOBILE]], [\n\n // Huawei\n /\\b((?:ag[rs][23]?|bah2?|sht?|btv)-a?[lw]\\d{2})\\b(?!.+d\\/s)/i\n ], [MODEL, [VENDOR, HUAWEI], [TYPE, TABLET]], [\n /(?:huawei|honor)([-\\w ]+)[;\\)]/i,\n /\\b(nexus 6p|\\w{2,4}e?-[atu]?[ln][\\dx][012359c][adn]?)\\b(?!.+d\\/s)/i\n ], [MODEL, [VENDOR, HUAWEI], [TYPE, MOBILE]], [\n\n // Xiaomi\n /\\b(poco[\\w ]+|m2\\d{3}j\\d\\d[a-z]{2})(?: bui|\\))/i, // Xiaomi POCO\n /\\b; (\\w+) build\\/hm\\1/i, // Xiaomi Hongmi 'numeric' models\n /\\b(hm[-_ ]?note?[_ ]?(?:\\d\\w)?) bui/i, // Xiaomi Hongmi\n /\\b(redmi[\\-_ ]?(?:note|k)?[\\w_ ]+)(?: bui|\\))/i, // Xiaomi Redmi\n /oid[^\\)]+; (m?[12][0-389][01]\\w{3,6}[c-y])( bui|; wv|\\))/i, // Xiaomi Redmi 'numeric' models\n /\\b(mi[-_ ]?(?:a\\d|one|one[_ ]plus|note lte|max|cc)?[_ ]?(?:\\d?\\w?)[_ ]?(?:plus|se|lite)?)(?: bui|\\))/i // Xiaomi Mi\n ], [[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, MOBILE]], [\n /oid[^\\)]+; (2\\d{4}(283|rpbf)[cgl])( bui|\\))/i, // Redmi Pad\n /\\b(mi[-_ ]?(?:pad)(?:[\\w_ ]+))(?: bui|\\))/i // Mi Pad tablets\n ],[[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, TABLET]], [\n\n // OPPO\n /; (\\w+) bui.+ oppo/i,\n /\\b(cph[12]\\d{3}|p(?:af|c[al]|d\\w|e[ar])[mt]\\d0|x9007|a101op)\\b/i\n ], [MODEL, [VENDOR, 'OPPO'], [TYPE, MOBILE]], [\n\n // Vivo\n /vivo (\\w+)(?: bui|\\))/i,\n /\\b(v[12]\\d{3}\\w?[at])(?: bui|;)/i\n ], [MODEL, [VENDOR, 'Vivo'], [TYPE, MOBILE]], [\n\n // Realme\n /\\b(rmx[1-3]\\d{3})(?: bui|;|\\))/i\n ], [MODEL, [VENDOR, 'Realme'], [TYPE, MOBILE]], [\n\n // Motorola\n /\\b(milestone|droid(?:[2-4x]| (?:bionic|x2|pro|razr))?:?( 4g)?)\\b[\\w ]+build\\//i,\n /\\bmot(?:orola)?[- ](\\w*)/i,\n /((?:moto[\\w\\(\\) ]+|xt\\d{3,4}|nexus 6)(?= bui|\\)))/i\n ], [MODEL, [VENDOR, MOTOROLA], [TYPE, MOBILE]], [\n /\\b(mz60\\d|xoom[2 ]{0,2}) build\\//i\n ], [MODEL, [VENDOR, MOTOROLA], [TYPE, TABLET]], [\n\n // LG\n /((?=lg)?[vl]k\\-?\\d{3}) bui| 3\\.[-\\w; ]{10}lg?-([06cv9]{3,4})/i\n ], [MODEL, [VENDOR, LG], [TYPE, TABLET]], [\n /(lm(?:-?f100[nv]?|-[\\w\\.]+)(?= bui|\\))|nexus [45])/i,\n /\\blg[-e;\\/ ]+((?!browser|netcast|android tv)\\w+)/i,\n /\\blg-?([\\d\\w]+) bui/i\n ], [MODEL, [VENDOR, LG], [TYPE, MOBILE]], [\n\n // Lenovo\n /(ideatab[-\\w ]+)/i,\n /lenovo ?(s[56]000[-\\w]+|tab(?:[\\w ]+)|yt[-\\d\\w]{6}|tb[-\\d\\w]{6})/i\n ], [MODEL, [VENDOR, 'Lenovo'], [TYPE, TABLET]], [\n\n // Nokia\n /(?:maemo|nokia).*(n900|lumia \\d+)/i,\n /nokia[-_ ]?([-\\w\\.]*)/i\n ], [[MODEL, /_/g, ' '], [VENDOR, 'Nokia'], [TYPE, MOBILE]], [\n\n // Google\n /(pixel c)\\b/i // Google Pixel C\n ], [MODEL, [VENDOR, GOOGLE], [TYPE, TABLET]], [\n /droid.+; (pixel[\\daxl ]{0,6})(?: bui|\\))/i // Google Pixel\n ], [MODEL, [VENDOR, GOOGLE], [TYPE, MOBILE]], [\n\n // Sony\n /droid.+ (a?\\d[0-2]{2}so|[c-g]\\d{4}|so[-gl]\\w+|xq-a\\w[4-7][12])(?= bui|\\).+chrome\\/(?![1-6]{0,1}\\d\\.))/i\n ], [MODEL, [VENDOR, SONY], [TYPE, MOBILE]], [\n /sony tablet [ps]/i,\n /\\b(?:sony)?sgp\\w+(?: bui|\\))/i\n ], [[MODEL, 'Xperia Tablet'], [VENDOR, SONY], [TYPE, TABLET]], [\n\n // OnePlus\n / (kb2005|in20[12]5|be20[12][59])\\b/i,\n /(?:one)?(?:plus)? (a\\d0\\d\\d)(?: b|\\))/i\n ], [MODEL, [VENDOR, 'OnePlus'], [TYPE, MOBILE]], [\n\n // Amazon\n /(alexa)webm/i,\n /(kf[a-z]{2}wi|aeo[c-r]{2})( bui|\\))/i, // Kindle Fire without Silk / Echo Show\n /(kf[a-z]+)( bui|\\)).+silk\\//i // Kindle Fire HD\n ], [MODEL, [VENDOR, AMAZON], [TYPE, TABLET]], [\n /((?:sd|kf)[0349hijorstuw]+)( bui|\\)).+silk\\//i // Fire Phone\n ], [[MODEL, /(.+)/g, 'Fire Phone $1'], [VENDOR, AMAZON], [TYPE, MOBILE]], [\n\n // BlackBerry\n /(playbook);[-\\w\\),; ]+(rim)/i // BlackBerry PlayBook\n ], [MODEL, VENDOR, [TYPE, TABLET]], [\n /\\b((?:bb[a-f]|st[hv])100-\\d)/i,\n /\\(bb10; (\\w+)/i // BlackBerry 10\n ], [MODEL, [VENDOR, BLACKBERRY], [TYPE, MOBILE]], [\n\n // Asus\n /(?:\\b|asus_)(transfo[prime ]{4,10} \\w+|eeepc|slider \\w+|nexus 7|padfone|p00[cj])/i\n ], [MODEL, [VENDOR, ASUS], [TYPE, TABLET]], [\n / (z[bes]6[027][012][km][ls]|zenfone \\d\\w?)\\b/i\n ], [MODEL, [VENDOR, ASUS], [TYPE, MOBILE]], [\n\n // HTC\n /(nexus 9)/i // HTC Nexus 9\n ], [MODEL, [VENDOR, 'HTC'], [TYPE, TABLET]], [\n /(htc)[-;_ ]{1,2}([\\w ]+(?=\\)| bui)|\\w+)/i, // HTC\n\n // ZTE\n /(zte)[- ]([\\w ]+?)(?: bui|\\/|\\))/i,\n /(alcatel|geeksphone|nexian|panasonic(?!(?:;|\\.))|sony(?!-bra))[-_ ]?([-\\w]*)/i // Alcatel/GeeksPhone/Nexian/Panasonic/Sony\n ], [VENDOR, [MODEL, /_/g, ' '], [TYPE, MOBILE]], [\n\n // Acer\n /droid.+; ([ab][1-7]-?[0178a]\\d\\d?)/i\n ], [MODEL, [VENDOR, 'Acer'], [TYPE, TABLET]], [\n\n // Meizu\n /droid.+; (m[1-5] note) bui/i,\n /\\bmz-([-\\w]{2,})/i\n ], [MODEL, [VENDOR, 'Meizu'], [TYPE, MOBILE]], [\n \n // Ulefone\n /; ((?:power )?armor(?:[\\w ]{0,8}))(?: bui|\\))/i\n ], [MODEL, [VENDOR, 'Ulefone'], [TYPE, MOBILE]], [\n\n // MIXED\n /(blackberry|benq|palm(?=\\-)|sonyericsson|acer|asus|dell|meizu|motorola|polytron|infinix|tecno)[-_ ]?([-\\w]*)/i,\n // BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron\n /(hp) ([\\w ]+\\w)/i, // HP iPAQ\n /(asus)-?(\\w+)/i, // Asus\n /(microsoft); (lumia[\\w ]+)/i, // Microsoft Lumia\n /(lenovo)[-_ ]?([-\\w]+)/i, // Lenovo\n /(jolla)/i, // Jolla\n /(oppo) ?([\\w ]+) bui/i // OPPO\n ], [VENDOR, MODEL, [TYPE, MOBILE]], [\n\n /(kobo)\\s(ereader|touch)/i, // Kobo\n /(archos) (gamepad2?)/i, // Archos\n /(hp).+(touchpad(?!.+tablet)|tablet)/i, // HP TouchPad\n /(kindle)\\/([\\w\\.]+)/i, // Kindle\n /(nook)[\\w ]+build\\/(\\w+)/i, // Nook\n /(dell) (strea[kpr\\d ]*[\\dko])/i, // Dell Streak\n /(le[- ]+pan)[- ]+(\\w{1,9}) bui/i, // Le Pan Tablets\n /(trinity)[- ]*(t\\d{3}) bui/i, // Trinity Tablets\n /(gigaset)[- ]+(q\\w{1,9}) bui/i, // Gigaset Tablets\n /(vodafone) ([\\w ]+)(?:\\)| bui)/i // Vodafone\n ], [VENDOR, MODEL, [TYPE, TABLET]], [\n\n /(surface duo)/i // Surface Duo\n ], [MODEL, [VENDOR, MICROSOFT], [TYPE, TABLET]], [\n /droid [\\d\\.]+; (fp\\du?)(?: b|\\))/i // Fairphone\n ], [MODEL, [VENDOR, 'Fairphone'], [TYPE, MOBILE]], [\n /(u304aa)/i // AT&T\n ], [MODEL, [VENDOR, 'AT&T'], [TYPE, MOBILE]], [\n /\\bsie-(\\w*)/i // Siemens\n ], [MODEL, [VENDOR, 'Siemens'], [TYPE, MOBILE]], [\n /\\b(rct\\w+) b/i // RCA Tablets\n ], [MODEL, [VENDOR, 'RCA'], [TYPE, TABLET]], [\n /\\b(venue[\\d ]{2,7}) b/i // Dell Venue Tablets\n ], [MODEL, [VENDOR, 'Dell'], [TYPE, TABLET]], [\n /\\b(q(?:mv|ta)\\w+) b/i // Verizon Tablet\n ], [MODEL, [VENDOR, 'Verizon'], [TYPE, TABLET]], [\n /\\b(?:barnes[& ]+noble |bn[rt])([\\w\\+ ]*) b/i // Barnes & Noble Tablet\n ], [MODEL, [VENDOR, 'Barnes & Noble'], [TYPE, TABLET]], [\n /\\b(tm\\d{3}\\w+) b/i\n ], [MODEL, [VENDOR, 'NuVision'], [TYPE, TABLET]], [\n /\\b(k88) b/i // ZTE K Series Tablet\n ], [MODEL, [VENDOR, 'ZTE'], [TYPE, TABLET]], [\n /\\b(nx\\d{3}j) b/i // ZTE Nubia\n ], [MODEL, [VENDOR, 'ZTE'], [TYPE, MOBILE]], [\n /\\b(gen\\d{3}) b.+49h/i // Swiss GEN Mobile\n ], [MODEL, [VENDOR, 'Swiss'], [TYPE, MOBILE]], [\n /\\b(zur\\d{3}) b/i // Swiss ZUR Tablet\n ], [MODEL, [VENDOR, 'Swiss'], [TYPE, TABLET]], [\n /\\b((zeki)?tb.*\\b) b/i // Zeki Tablets\n ], [MODEL, [VENDOR, 'Zeki'], [TYPE, TABLET]], [\n /\\b([yr]\\d{2}) b/i,\n /\\b(dragon[- ]+touch |dt)(\\w{5}) b/i // Dragon Touch Tablet\n ], [[VENDOR, 'Dragon Touch'], MODEL, [TYPE, TABLET]], [\n /\\b(ns-?\\w{0,9}) b/i // Insignia Tablets\n ], [MODEL, [VENDOR, 'Insignia'], [TYPE, TABLET]], [\n /\\b((nxa|next)-?\\w{0,9}) b/i // NextBook Tablets\n ], [MODEL, [VENDOR, 'NextBook'], [TYPE, TABLET]], [\n /\\b(xtreme\\_)?(v(1[045]|2[015]|[3469]0|7[05])) b/i // Voice Xtreme Phones\n ], [[VENDOR, 'Voice'], MODEL, [TYPE, MOBILE]], [\n /\\b(lvtel\\-)?(v1[12]) b/i // LvTel Phones\n ], [[VENDOR, 'LvTel'], MODEL, [TYPE, MOBILE]], [\n /\\b(ph-1) /i // Essential PH-1\n ], [MODEL, [VENDOR, 'Essential'], [TYPE, MOBILE]], [\n /\\b(v(100md|700na|7011|917g).*\\b) b/i // Envizen Tablets\n ], [MODEL, [VENDOR, 'Envizen'], [TYPE, TABLET]], [\n /\\b(trio[-\\w\\. ]+) b/i // MachSpeed Tablets\n ], [MODEL, [VENDOR, 'MachSpeed'], [TYPE, TABLET]], [\n /\\btu_(1491) b/i // Rotor Tablets\n ], [MODEL, [VENDOR, 'Rotor'], [TYPE, TABLET]], [\n /(shield[\\w ]+) b/i // Nvidia Shield Tablets\n ], [MODEL, [VENDOR, 'Nvidia'], [TYPE, TABLET]], [\n /(sprint) (\\w+)/i // Sprint Phones\n ], [VENDOR, MODEL, [TYPE, MOBILE]], [\n /(kin\\.[onetw]{3})/i // Microsoft Kin\n ], [[MODEL, /\\./g, ' '], [VENDOR, MICROSOFT], [TYPE, MOBILE]], [\n /droid.+; (cc6666?|et5[16]|mc[239][23]x?|vc8[03]x?)\\)/i // Zebra\n ], [MODEL, [VENDOR, ZEBRA], [TYPE, TABLET]], [\n /droid.+; (ec30|ps20|tc[2-8]\\d[kx])\\)/i\n ], [MODEL, [VENDOR, ZEBRA], [TYPE, MOBILE]], [\n\n ///////////////////\n // SMARTTVS\n ///////////////////\n\n /smart-tv.+(samsung)/i // Samsung\n ], [VENDOR, [TYPE, SMARTTV]], [\n /hbbtv.+maple;(\\d+)/i\n ], [[MODEL, /^/, 'SmartTV'], [VENDOR, SAMSUNG], [TYPE, SMARTTV]], [\n /(nux; netcast.+smarttv|lg (netcast\\.tv-201\\d|android tv))/i // LG SmartTV\n ], [[VENDOR, LG], [TYPE, SMARTTV]], [\n /(apple) ?tv/i // Apple TV\n ], [VENDOR, [MODEL, APPLE+' TV'], [TYPE, SMARTTV]], [\n /crkey/i // Google Chromecast\n ], [[MODEL, CHROME+'cast'], [VENDOR, GOOGLE], [TYPE, SMARTTV]], [\n /droid.+aft(\\w+)( bui|\\))/i // Fire TV\n ], [MODEL, [VENDOR, AMAZON], [TYPE, SMARTTV]], [\n /\\(dtv[\\);].+(aquos)/i,\n /(aquos-tv[\\w ]+)\\)/i // Sharp\n ], [MODEL, [VENDOR, SHARP], [TYPE, SMARTTV]],[\n /(bravia[\\w ]+)( bui|\\))/i // Sony\n ], [MODEL, [VENDOR, SONY], [TYPE, SMARTTV]], [\n /(mitv-\\w{5}) bui/i // Xiaomi\n ], [MODEL, [VENDOR, XIAOMI], [TYPE, SMARTTV]], [\n /Hbbtv.*(technisat) (.*);/i // TechniSAT\n ], [VENDOR, MODEL, [TYPE, SMARTTV]], [\n /\\b(roku)[\\dx]*[\\)\\/]((?:dvp-)?[\\d\\.]*)/i, // Roku\n /hbbtv\\/\\d+\\.\\d+\\.\\d+ +\\([\\w\\+ ]*; *([\\w\\d][^;]*);([^;]*)/i // HbbTV devices\n ], [[VENDOR, trim], [MODEL, trim], [TYPE, SMARTTV]], [\n /\\b(android tv|smart[- ]?tv|opera tv|tv; rv:)\\b/i // SmartTV from Unidentified Vendors\n ], [[TYPE, SMARTTV]], [\n\n ///////////////////\n // CONSOLES\n ///////////////////\n\n /(ouya)/i, // Ouya\n /(nintendo) ([wids3utch]+)/i // Nintendo\n ], [VENDOR, MODEL, [TYPE, CONSOLE]], [\n /droid.+; (shield) bui/i // Nvidia\n ], [MODEL, [VENDOR, 'Nvidia'], [TYPE, CONSOLE]], [\n /(playstation [345portablevi]+)/i // Playstation\n ], [MODEL, [VENDOR, SONY], [TYPE, CONSOLE]], [\n /\\b(xbox(?: one)?(?!; xbox))[\\); ]/i // Microsoft Xbox\n ], [MODEL, [VENDOR, MICROSOFT], [TYPE, CONSOLE]], [\n\n ///////////////////\n // WEARABLES\n ///////////////////\n\n /((pebble))app/i // Pebble\n ], [VENDOR, MODEL, [TYPE, WEARABLE]], [\n /(watch)(?: ?os[,\\/]|\\d,\\d\\/)[\\d\\.]+/i // Apple Watch\n ], [MODEL, [VENDOR, APPLE], [TYPE, WEARABLE]], [\n /droid.+; (glass) \\d/i // Google Glass\n ], [MODEL, [VENDOR, GOOGLE], [TYPE, WEARABLE]], [\n /droid.+; (wt63?0{2,3})\\)/i\n ], [MODEL, [VENDOR, ZEBRA], [TYPE, WEARABLE]], [\n /(quest( 2| pro)?)/i // Oculus Quest\n ], [MODEL, [VENDOR, FACEBOOK], [TYPE, WEARABLE]], [\n\n ///////////////////\n // EMBEDDED\n ///////////////////\n\n /(tesla)(?: qtcarbrowser|\\/[-\\w\\.]+)/i // Tesla\n ], [VENDOR, [TYPE, EMBEDDED]], [\n /(aeobc)\\b/i // Echo Dot\n ], [MODEL, [VENDOR, AMAZON], [TYPE, EMBEDDED]], [\n\n ////////////////////\n // MIXED (GENERIC)\n ///////////////////\n\n /droid .+?; ([^;]+?)(?: bui|; wv\\)|\\) applew).+? mobile safari/i // Android Phones from Unidentified Vendors\n ], [MODEL, [TYPE, MOBILE]], [\n /droid .+?; ([^;]+?)(?: bui|\\) applew).+?(?! mobile) safari/i // Android Tablets from Unidentified Vendors\n ], [MODEL, [TYPE, TABLET]], [\n /\\b((tablet|tab)[;\\/]|focus\\/\\d(?!.+mobile))/i // Unidentifiable Tablet\n ], [[TYPE, TABLET]], [\n /(phone|mobile(?:[;\\/]| [ \\w\\/\\.]*safari)|pda(?=.+windows ce))/i // Unidentifiable Mobile\n ], [[TYPE, MOBILE]], [\n /(android[-\\w\\. ]{0,9});.+buil/i // Generic Android Device\n ], [MODEL, [VENDOR, 'Generic']]\n ],\n\n engine : [[\n\n /windows.+ edge\\/([\\w\\.]+)/i // EdgeHTML\n ], [VERSION, [NAME, EDGE+'HTML']], [\n\n /webkit\\/537\\.36.+chrome\\/(?!27)([\\w\\.]+)/i // Blink\n ], [VERSION, [NAME, 'Blink']], [\n\n /(presto)\\/([\\w\\.]+)/i, // Presto\n /(webkit|trident|netfront|netsurf|amaya|lynx|w3m|goanna)\\/([\\w\\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m/Goanna\n /ekioh(flow)\\/([\\w\\.]+)/i, // Flow\n /(khtml|tasman|links)[\\/ ]\\(?([\\w\\.]+)/i, // KHTML/Tasman/Links\n /(icab)[\\/ ]([23]\\.[\\d\\.]+)/i, // iCab\n /\\b(libweb)/i\n ], [NAME, VERSION], [\n\n /rv\\:([\\w\\.]{1,9})\\b.+(gecko)/i // Gecko\n ], [VERSION, NAME]\n ],\n\n os : [[\n\n // Windows\n /microsoft (windows) (vista|xp)/i // Windows (iTunes)\n ], [NAME, VERSION], [\n /(windows (?:phone(?: os)?|mobile))[\\/ ]?([\\d\\.\\w ]*)/i // Windows Phone\n ], [NAME, [VERSION, strMapper, windowsVersionMap]], [\n /windows nt 6\\.2; (arm)/i, // Windows RT\n /windows[\\/ ]?([ntce\\d\\. ]+\\w)(?!.+xbox)/i,\n /(?:win(?=3|9|n)|win 9x )([nt\\d\\.]+)/i\n ], [[VERSION, strMapper, windowsVersionMap], [NAME, 'Windows']], [\n\n // iOS/macOS\n /ip[honead]{2,4}\\b(?:.*os ([\\w]+) like mac|; opera)/i, // iOS\n /(?:ios;fbsv\\/|iphone.+ios[\\/ ])([\\d\\.]+)/i,\n /cfnetwork\\/.+darwin/i\n ], [[VERSION, /_/g, '.'], [NAME, 'iOS']], [\n /(mac os x) ?([\\w\\. ]*)/i,\n /(macintosh|mac_powerpc\\b)(?!.+haiku)/i // Mac OS\n ], [[NAME, MAC_OS], [VERSION, /_/g, '.']], [\n\n // Mobile OSes\n /droid ([\\w\\.]+)\\b.+(android[- ]x86|harmonyos)/i // Android-x86/HarmonyOS\n ], [VERSION, NAME], [ // Android/WebOS/QNX/Bada/RIM/Maemo/MeeGo/Sailfish OS\n /(android|webos|qnx|bada|rim tablet os|maemo|meego|sailfish)[-\\/ ]?([\\w\\.]*)/i,\n /(blackberry)\\w*\\/([\\w\\.]*)/i, // Blackberry\n /(tizen|kaios)[\\/ ]([\\w\\.]+)/i, // Tizen/KaiOS\n /\\((series40);/i // Series 40\n ], [NAME, VERSION], [\n /\\(bb(10);/i // BlackBerry 10\n ], [VERSION, [NAME, BLACKBERRY]], [\n /(?:symbian ?os|symbos|s60(?=;)|series60)[-\\/ ]?([\\w\\.]*)/i // Symbian\n ], [VERSION, [NAME, 'Symbian']], [\n /mozilla\\/[\\d\\.]+ \\((?:mobile|tablet|tv|mobile; [\\w ]+); rv:.+ gecko\\/([\\w\\.]+)/i // Firefox OS\n ], [VERSION, [NAME, FIREFOX+' OS']], [\n /web0s;.+rt(tv)/i,\n /\\b(?:hp)?wos(?:browser)?\\/([\\w\\.]+)/i // WebOS\n ], [VERSION, [NAME, 'webOS']], [\n /watch(?: ?os[,\\/]|\\d,\\d\\/)([\\d\\.]+)/i // watchOS\n ], [VERSION, [NAME, 'watchOS']], [\n\n // Google Chromecast\n /crkey\\/([\\d\\.]+)/i // Google Chromecast\n ], [VERSION, [NAME, CHROME+'cast']], [\n /(cros) [\\w]+(?:\\)| ([\\w\\.]+)\\b)/i // Chromium OS\n ], [[NAME, CHROMIUM_OS], VERSION],[\n\n // Smart TVs\n /panasonic;(viera)/i, // Panasonic Viera\n /(netrange)mmh/i, // Netrange\n /(nettv)\\/(\\d+\\.[\\w\\.]+)/i, // NetTV\n\n // Console\n /(nintendo|playstation) ([wids345portablevuch]+)/i, // Nintendo/Playstation\n /(xbox); +xbox ([^\\);]+)/i, // Microsoft Xbox (360, One, X, S, Series X, Series S)\n\n // Other\n /\\b(joli|palm)\\b ?(?:os)?\\/?([\\w\\.]*)/i, // Joli/Palm\n /(mint)[\\/\\(\\) ]?(\\w*)/i, // Mint\n /(mageia|vectorlinux)[; ]/i, // Mageia/VectorLinux\n /([kxln]?ubuntu|debian|suse|opensuse|gentoo|arch(?= linux)|slackware|fedora|mandriva|centos|pclinuxos|red ?hat|zenwalk|linpus|raspbian|plan 9|minix|risc os|contiki|deepin|manjaro|elementary os|sabayon|linspire)(?: gnu\\/linux)?(?: enterprise)?(?:[- ]linux)?(?:-gnu)?[-\\/ ]?(?!chrom|package)([-\\w\\.]*)/i,\n // Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware/Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus/Raspbian/Plan9/Minix/RISCOS/Contiki/Deepin/Manjaro/elementary/Sabayon/Linspire\n /(hurd|linux) ?([\\w\\.]*)/i, // Hurd/Linux\n /(gnu) ?([\\w\\.]*)/i, // GNU\n /\\b([-frentopcghs]{0,5}bsd|dragonfly)[\\/ ]?(?!amd|[ix346]{1,2}86)([\\w\\.]*)/i, // FreeBSD/NetBSD/OpenBSD/PC-BSD/GhostBSD/DragonFly\n /(haiku) (\\w+)/i // Haiku\n ], [NAME, VERSION], [\n /(sunos) ?([\\w\\.\\d]*)/i // Solaris\n ], [[NAME, 'Solaris'], VERSION], [\n /((?:open)?solaris)[-\\/ ]?([\\w\\.]*)/i, // Solaris\n /(aix) ((\\d)(?=\\.|\\)| )[\\w\\.])*/i, // AIX\n /\\b(beos|os\\/2|amigaos|morphos|openvms|fuchsia|hp-ux|serenityos)/i, // BeOS/OS2/AmigaOS/MorphOS/OpenVMS/Fuchsia/HP-UX/SerenityOS\n /(unix) ?([\\w\\.]*)/i // UNIX\n ], [NAME, VERSION]\n ]\n };\n\n /////////////////\n // Constructor\n ////////////////\n\n var UAParser = function (ua, extensions) {\n\n if (typeof ua === OBJ_TYPE) {\n extensions = ua;\n ua = undefined;\n }\n\n if (!(this instanceof UAParser)) {\n return new UAParser(ua, extensions).getResult();\n }\n\n var _navigator = (typeof window !== UNDEF_TYPE && window.navigator) ? window.navigator : undefined;\n var _ua = ua || ((_navigator && _navigator.userAgent) ? _navigator.userAgent : EMPTY);\n var _uach = (_navigator && _navigator.userAgentData) ? _navigator.userAgentData : undefined;\n var _rgxmap = extensions ? extend(regexes, extensions) : regexes;\n var _isSelfNav = _navigator && _navigator.userAgent == _ua;\n\n this.getBrowser = function () {\n var _browser = {};\n _browser[NAME] = undefined;\n _browser[VERSION] = undefined;\n rgxMapper.call(_browser, _ua, _rgxmap.browser);\n _browser[MAJOR] = majorize(_browser[VERSION]);\n // Brave-specific detection\n if (_isSelfNav && _navigator && _navigator.brave && typeof _navigator.brave.isBrave == FUNC_TYPE) {\n _browser[NAME] = 'Brave';\n }\n return _browser;\n };\n this.getCPU = function () {\n var _cpu = {};\n _cpu[ARCHITECTURE] = undefined;\n rgxMapper.call(_cpu, _ua, _rgxmap.cpu);\n return _cpu;\n };\n this.getDevice = function () {\n var _device = {};\n _device[VENDOR] = undefined;\n _device[MODEL] = undefined;\n _device[TYPE] = undefined;\n rgxMapper.call(_device, _ua, _rgxmap.device);\n if (_isSelfNav && !_device[TYPE] && _uach && _uach.mobile) {\n _device[TYPE] = MOBILE;\n }\n // iPadOS-specific detection: identified as Mac, but has some iOS-only properties\n if (_isSelfNav && _device[MODEL] == 'Macintosh' && _navigator && typeof _navigator.standalone !== UNDEF_TYPE && _navigator.maxTouchPoints && _navigator.maxTouchPoints > 2) {\n _device[MODEL] = 'iPad';\n _device[TYPE] = TABLET;\n }\n return _device;\n };\n this.getEngine = function () {\n var _engine = {};\n _engine[NAME] = undefined;\n _engine[VERSION] = undefined;\n rgxMapper.call(_engine, _ua, _rgxmap.engine);\n return _engine;\n };\n this.getOS = function () {\n var _os = {};\n _os[NAME] = undefined;\n _os[VERSION] = undefined;\n rgxMapper.call(_os, _ua, _rgxmap.os);\n if (_isSelfNav && !_os[NAME] && _uach && _uach.platform != 'Unknown') {\n _os[NAME] = _uach.platform \n .replace(/chrome os/i, CHROMIUM_OS)\n .replace(/macos/i, MAC_OS); // backward compatibility\n }\n return _os;\n };\n this.getResult = function () {\n return {\n ua : this.getUA(),\n browser : this.getBrowser(),\n engine : this.getEngine(),\n os : this.getOS(),\n device : this.getDevice(),\n cpu : this.getCPU()\n };\n };\n this.getUA = function () {\n return _ua;\n };\n this.setUA = function (ua) {\n _ua = (typeof ua === STR_TYPE && ua.length > UA_MAX_LENGTH) ? trim(ua, UA_MAX_LENGTH) : ua;\n return this;\n };\n this.setUA(_ua);\n return this;\n };\n\n UAParser.VERSION = LIBVERSION;\n UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR]);\n UAParser.CPU = enumerize([ARCHITECTURE]);\n UAParser.DEVICE = enumerize([MODEL, VENDOR, TYPE, CONSOLE, MOBILE, SMARTTV, TABLET, WEARABLE, EMBEDDED]);\n UAParser.ENGINE = UAParser.OS = enumerize([NAME, VERSION]);\n\n ///////////\n // Export\n //////////\n\n // check js environment\n if (typeof(exports) !== UNDEF_TYPE) {\n // nodejs env\n if (typeof module !== UNDEF_TYPE && module.exports) {\n exports = module.exports = UAParser;\n }\n exports.UAParser = UAParser;\n } else {\n // requirejs env (optional)\n if (typeof(define) === FUNC_TYPE && define.amd) {\n define(function () {\n return UAParser;\n });\n } else if (typeof window !== UNDEF_TYPE) {\n // browser env\n window.UAParser = UAParser;\n }\n }\n\n // jQuery/Zepto specific (optional)\n // Note:\n // In AMD env the global scope should be kept clean, but jQuery is an exception.\n // jQuery always exports to global scope, unless jQuery.noConflict(true) is used,\n // and we should catch that.\n var $ = typeof window !== UNDEF_TYPE && (window.jQuery || window.Zepto);\n if ($ && !$.ua) {\n var parser = new UAParser();\n $.ua = parser.getResult();\n $.ua.get = function () {\n return parser.getUA();\n };\n $.ua.set = function (ua) {\n parser.setUA(ua);\n var result = parser.getResult();\n for (var prop in result) {\n $.ua[prop] = result[prop];\n }\n };\n }\n\n})(typeof window === 'object' ? window : this);\n","/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\nexport default freeGlobal;\n","import freeGlobal from './_freeGlobal.js';\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\nexport default root;\n","import root from './_root.js';\n\n/** Built-in value references. */\nvar Symbol = root.Symbol;\n\nexport default Symbol;\n","import Symbol from './_Symbol.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the raw `toStringTag`.\n */\nfunction getRawTag(value) {\n var isOwn = hasOwnProperty.call(value, symToStringTag),\n tag = value[symToStringTag];\n\n try {\n value[symToStringTag] = undefined;\n var unmasked = true;\n } catch (e) {}\n\n var result = nativeObjectToString.call(value);\n if (unmasked) {\n if (isOwn) {\n value[symToStringTag] = tag;\n } else {\n delete value[symToStringTag];\n }\n }\n return result;\n}\n\nexport default getRawTag;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","import Symbol from './_Symbol.js';\nimport getRawTag from './_getRawTag.js';\nimport objectToString from './_objectToString.js';\n\n/** `Object#toString` result references. */\nvar nullTag = '[object Null]',\n undefinedTag = '[object Undefined]';\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * The base implementation of `getTag` without fallbacks for buggy environments.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nfunction baseGetTag(value) {\n if (value == null) {\n return value === undefined ? undefinedTag : nullTag;\n }\n return (symToStringTag && symToStringTag in Object(value))\n ? getRawTag(value)\n : objectToString(value);\n}\n\nexport default baseGetTag;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","import baseGetTag from './_baseGetTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar symbolTag = '[object Symbol]';\n\n/**\n * Checks if `value` is classified as a `Symbol` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\nfunction isSymbol(value) {\n return typeof value == 'symbol' ||\n (isObjectLike(value) && baseGetTag(value) == symbolTag);\n}\n\nexport default isSymbol;\n","/** Used to match a single whitespace character. */\nvar reWhitespace = /\\s/;\n\n/**\n * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace\n * character of `string`.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {number} Returns the index of the last non-whitespace character.\n */\nfunction trimmedEndIndex(string) {\n var index = string.length;\n\n while (index-- && reWhitespace.test(string.charAt(index))) {}\n return index;\n}\n\nexport default trimmedEndIndex;\n","import trimmedEndIndex from './_trimmedEndIndex.js';\n\n/** Used to match leading whitespace. */\nvar reTrimStart = /^\\s+/;\n\n/**\n * The base implementation of `_.trim`.\n *\n * @private\n * @param {string} string The string to trim.\n * @returns {string} Returns the trimmed string.\n */\nfunction baseTrim(string) {\n return string\n ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '')\n : string;\n}\n\nexport default baseTrim;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","import baseTrim from './_baseTrim.js';\nimport isObject from './isObject.js';\nimport isSymbol from './isSymbol.js';\n\n/** Used as references for various `Number` constants. */\nvar NAN = 0 / 0;\n\n/** Used to detect bad signed hexadecimal string values. */\nvar reIsBadHex = /^[-+]0x[0-9a-f]+$/i;\n\n/** Used to detect binary string values. */\nvar reIsBinary = /^0b[01]+$/i;\n\n/** Used to detect octal string values. */\nvar reIsOctal = /^0o[0-7]+$/i;\n\n/** Built-in method references without a dependency on `root`. */\nvar freeParseInt = parseInt;\n\n/**\n * Converts `value` to a number.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to process.\n * @returns {number} Returns the number.\n * @example\n *\n * _.toNumber(3.2);\n * // => 3.2\n *\n * _.toNumber(Number.MIN_VALUE);\n * // => 5e-324\n *\n * _.toNumber(Infinity);\n * // => Infinity\n *\n * _.toNumber('3.2');\n * // => 3.2\n */\nfunction toNumber(value) {\n if (typeof value == 'number') {\n return value;\n }\n if (isSymbol(value)) {\n return NAN;\n }\n if (isObject(value)) {\n var other = typeof value.valueOf == 'function' ? value.valueOf() : value;\n value = isObject(other) ? (other + '') : other;\n }\n if (typeof value != 'string') {\n return value === 0 ? value : +value;\n }\n value = baseTrim(value);\n var isBinary = reIsBinary.test(value);\n return (isBinary || reIsOctal.test(value))\n ? freeParseInt(value.slice(2), isBinary ? 2 : 8)\n : (reIsBadHex.test(value) ? NAN : +value);\n}\n\nexport default toNumber;\n","/**\n * The base implementation of `_.clamp` which doesn't coerce arguments.\n *\n * @private\n * @param {number} number The number to clamp.\n * @param {number} [lower] The lower bound.\n * @param {number} upper The upper bound.\n * @returns {number} Returns the clamped number.\n */\nfunction baseClamp(number, lower, upper) {\n if (number === number) {\n if (upper !== undefined) {\n number = number <= upper ? number : upper;\n }\n if (lower !== undefined) {\n number = number >= lower ? number : lower;\n }\n }\n return number;\n}\n\nexport default baseClamp;\n","import baseClamp from './_baseClamp.js';\nimport toNumber from './toNumber.js';\n\n/**\n * Clamps `number` within the inclusive `lower` and `upper` bounds.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Number\n * @param {number} number The number to clamp.\n * @param {number} [lower] The lower bound.\n * @param {number} upper The upper bound.\n * @returns {number} Returns the clamped number.\n * @example\n *\n * _.clamp(-10, -5, 5);\n * // => -5\n *\n * _.clamp(10, -5, 5);\n * // => 5\n */\nfunction clamp(number, lower, upper) {\n if (upper === undefined) {\n upper = lower;\n lower = undefined;\n }\n if (upper !== undefined) {\n upper = toNumber(upper);\n upper = upper === upper ? upper : 0;\n }\n if (lower !== undefined) {\n lower = toNumber(lower);\n lower = lower === lower ? lower : 0;\n }\n return baseClamp(toNumber(number), lower, upper);\n}\n\nexport default clamp;\n","function addUniqueItem(array, item) {\n array.indexOf(item) === -1 && array.push(item);\n}\nfunction removeItem(arr, item) {\n const index = arr.indexOf(item);\n index > -1 && arr.splice(index, 1);\n}\n\nexport { addUniqueItem, removeItem };\n","const clamp = (min, max, v) => Math.min(Math.max(v, min), max);\n\nexport { clamp };\n","const defaults = {\n duration: 0.3,\n delay: 0,\n endDelay: 0,\n repeat: 0,\n easing: \"ease\",\n};\n\nexport { defaults };\n","const isNumber = (value) => typeof value === \"number\";\n\nexport { isNumber };\n","import { isNumber } from './is-number.es.js';\n\nconst isEasingList = (easing) => Array.isArray(easing) && !isNumber(easing[0]);\n\nexport { isEasingList };\n","const wrap = (min, max, v) => {\n const rangeSize = max - min;\n return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min;\n};\n\nexport { wrap };\n","import { isEasingList } from './is-easing-list.es.js';\nimport { wrap } from './wrap.es.js';\n\nfunction getEasingForSegment(easing, i) {\n return isEasingList(easing)\n ? easing[wrap(0, easing.length, i)]\n : easing;\n}\n\nexport { getEasingForSegment };\n","const mix = (min, max, progress) => -progress * min + progress * max + min;\n\nexport { mix };\n","const noop = () => { };\nconst noopReturn = (v) => v;\n\nexport { noop, noopReturn };\n","const progress = (min, max, value) => max - min === 0 ? 1 : (value - min) / (max - min);\n\nexport { progress };\n","import { mix } from './mix.es.js';\nimport { progress } from './progress.es.js';\n\nfunction fillOffset(offset, remaining) {\n const min = offset[offset.length - 1];\n for (let i = 1; i <= remaining; i++) {\n const offsetProgress = progress(0, remaining, i);\n offset.push(mix(min, 1, offsetProgress));\n }\n}\nfunction defaultOffset(length) {\n const offset = [0];\n fillOffset(offset, length - 1);\n return offset;\n}\n\nexport { defaultOffset, fillOffset };\n","import { mix } from './mix.es.js';\nimport { noopReturn } from './noop.es.js';\nimport { fillOffset, defaultOffset } from './offset.es.js';\nimport { progress } from './progress.es.js';\nimport { getEasingForSegment } from './easing.es.js';\nimport { clamp } from './clamp.es.js';\n\nfunction interpolate(output, input = defaultOffset(output.length), easing = noopReturn) {\n const length = output.length;\n /**\n * If the input length is lower than the output we\n * fill the input to match. This currently assumes the input\n * is an animation progress value so is a good candidate for\n * moving outside the function.\n */\n const remainder = length - input.length;\n remainder > 0 && fillOffset(input, remainder);\n return (t) => {\n let i = 0;\n for (; i < length - 2; i++) {\n if (t < input[i + 1])\n break;\n }\n let progressInRange = clamp(0, 1, progress(input[i], input[i + 1], t));\n const segmentEasing = getEasingForSegment(easing, i);\n progressInRange = segmentEasing(progressInRange);\n return mix(output[i], output[i + 1], progressInRange);\n };\n}\n\nexport { interpolate };\n","import { isNumber } from './is-number.es.js';\n\nconst isCubicBezier = (easing) => Array.isArray(easing) && isNumber(easing[0]);\n\nexport { isCubicBezier };\n","const isEasingGenerator = (easing) => typeof easing === \"object\" &&\n Boolean(easing.createAnimation);\n\nexport { isEasingGenerator };\n","const isFunction = (value) => typeof value === \"function\";\n\nexport { isFunction };\n","const isString = (value) => typeof value === \"string\";\n\nexport { isString };\n","const time = {\n ms: (seconds) => seconds * 1000,\n s: (milliseconds) => milliseconds / 1000,\n};\n\nexport { time };\n","import { noopReturn } from '@motionone/utils';\n\n/*\n Bezier function generator\n\n This has been modified from Gaëtan Renaudeau's BezierEasing\n https://github.com/gre/bezier-easing/blob/master/src/index.js\n https://github.com/gre/bezier-easing/blob/master/LICENSE\n \n I've removed the newtonRaphsonIterate algo because in benchmarking it\n wasn't noticiably faster than binarySubdivision, indeed removing it\n usually improved times, depending on the curve.\n\n I also removed the lookup table, as for the added bundle size and loop we're\n only cutting ~4 or so subdivision iterations. I bumped the max iterations up\n to 12 to compensate and this still tended to be faster for no perceivable\n loss in accuracy.\n\n Usage\n const easeOut = cubicBezier(.17,.67,.83,.67);\n const x = easeOut(0.5); // returns 0.627...\n*/\n// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.\nconst calcBezier = (t, a1, a2) => (((1.0 - 3.0 * a2 + 3.0 * a1) * t + (3.0 * a2 - 6.0 * a1)) * t + 3.0 * a1) * t;\nconst subdivisionPrecision = 0.0000001;\nconst subdivisionMaxIterations = 12;\nfunction binarySubdivide(x, lowerBound, upperBound, mX1, mX2) {\n let currentX;\n let currentT;\n let i = 0;\n do {\n currentT = lowerBound + (upperBound - lowerBound) / 2.0;\n currentX = calcBezier(currentT, mX1, mX2) - x;\n if (currentX > 0.0) {\n upperBound = currentT;\n }\n else {\n lowerBound = currentT;\n }\n } while (Math.abs(currentX) > subdivisionPrecision &&\n ++i < subdivisionMaxIterations);\n return currentT;\n}\nfunction cubicBezier(mX1, mY1, mX2, mY2) {\n // If this is a linear gradient, return linear easing\n if (mX1 === mY1 && mX2 === mY2)\n return noopReturn;\n const getTForX = (aX) => binarySubdivide(aX, 0, 1, mX1, mX2);\n // If animation is at start/end, return t without easing\n return (t) => t === 0 || t === 1 ? t : calcBezier(getTForX(t), mY1, mY2);\n}\n\nexport { cubicBezier };\n","import { clamp } from '@motionone/utils';\n\nconst steps = (steps, direction = \"end\") => (progress) => {\n progress =\n direction === \"end\"\n ? Math.min(progress, 0.999)\n : Math.max(progress, 0.001);\n const expanded = progress * steps;\n const rounded = direction === \"end\" ? Math.floor(expanded) : Math.ceil(expanded);\n return clamp(0, 1, rounded / steps);\n};\n\nexport { steps };\n","import { cubicBezier, steps } from '@motionone/easing';\nimport { isFunction, isCubicBezier, noopReturn } from '@motionone/utils';\n\nconst namedEasings = {\n ease: cubicBezier(0.25, 0.1, 0.25, 1.0),\n \"ease-in\": cubicBezier(0.42, 0.0, 1.0, 1.0),\n \"ease-in-out\": cubicBezier(0.42, 0.0, 0.58, 1.0),\n \"ease-out\": cubicBezier(0.0, 0.0, 0.58, 1.0),\n};\nconst functionArgsRegex = /\\((.*?)\\)/;\nfunction getEasingFunction(definition) {\n // If already an easing function, return\n if (isFunction(definition))\n return definition;\n // If an easing curve definition, return bezier function\n if (isCubicBezier(definition))\n return cubicBezier(...definition);\n // If we have a predefined easing function, return\n if (namedEasings[definition])\n return namedEasings[definition];\n // If this is a steps function, attempt to create easing curve\n if (definition.startsWith(\"steps\")) {\n const args = functionArgsRegex.exec(definition);\n if (args) {\n const argsArray = args[1].split(\",\");\n return steps(parseFloat(argsArray[0]), argsArray[1].trim());\n }\n }\n return noopReturn;\n}\n\nexport { getEasingFunction };\n","import { noopReturn, defaults, isEasingGenerator, isEasingList, interpolate } from '@motionone/utils';\nimport { getEasingFunction } from './utils/easing.es.js';\n\nclass Animation {\n constructor(output, keyframes = [0, 1], { easing, duration: initialDuration = defaults.duration, delay = defaults.delay, endDelay = defaults.endDelay, repeat = defaults.repeat, offset, direction = \"normal\", } = {}) {\n this.startTime = null;\n this.rate = 1;\n this.t = 0;\n this.cancelTimestamp = null;\n this.easing = noopReturn;\n this.duration = 0;\n this.totalDuration = 0;\n this.repeat = 0;\n this.playState = \"idle\";\n this.finished = new Promise((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n easing = easing || defaults.easing;\n if (isEasingGenerator(easing)) {\n const custom = easing.createAnimation(keyframes);\n easing = custom.easing;\n keyframes = custom.keyframes || keyframes;\n initialDuration = custom.duration || initialDuration;\n }\n this.repeat = repeat;\n this.easing = isEasingList(easing) ? noopReturn : getEasingFunction(easing);\n this.updateDuration(initialDuration);\n const interpolate$1 = interpolate(keyframes, offset, isEasingList(easing) ? easing.map(getEasingFunction) : noopReturn);\n this.tick = (timestamp) => {\n var _a;\n // TODO: Temporary fix for OptionsResolver typing\n delay = delay;\n let t = 0;\n if (this.pauseTime !== undefined) {\n t = this.pauseTime;\n }\n else {\n t = (timestamp - this.startTime) * this.rate;\n }\n this.t = t;\n // Convert to seconds\n t /= 1000;\n // Rebase on delay\n t = Math.max(t - delay, 0);\n /**\n * If this animation has finished, set the current time\n * to the total duration.\n */\n if (this.playState === \"finished\" && this.pauseTime === undefined) {\n t = this.totalDuration;\n }\n /**\n * Get the current progress (0-1) of the animation. If t is >\n * than duration we'll get values like 2.5 (midway through the\n * third iteration)\n */\n const progress = t / this.duration;\n // TODO progress += iterationStart\n /**\n * Get the current iteration (0 indexed). For instance the floor of\n * 2.5 is 2.\n */\n let currentIteration = Math.floor(progress);\n /**\n * Get the current progress of the iteration by taking the remainder\n * so 2.5 is 0.5 through iteration 2\n */\n let iterationProgress = progress % 1.0;\n if (!iterationProgress && progress >= 1) {\n iterationProgress = 1;\n }\n /**\n * If iteration progress is 1 we count that as the end\n * of the previous iteration.\n */\n iterationProgress === 1 && currentIteration--;\n /**\n * Reverse progress if we're not running in \"normal\" direction\n */\n const iterationIsOdd = currentIteration % 2;\n if (direction === \"reverse\" ||\n (direction === \"alternate\" && iterationIsOdd) ||\n (direction === \"alternate-reverse\" && !iterationIsOdd)) {\n iterationProgress = 1 - iterationProgress;\n }\n const p = t >= this.totalDuration ? 1 : Math.min(iterationProgress, 1);\n const latest = interpolate$1(this.easing(p));\n output(latest);\n const isAnimationFinished = this.pauseTime === undefined &&\n (this.playState === \"finished\" || t >= this.totalDuration + endDelay);\n if (isAnimationFinished) {\n this.playState = \"finished\";\n (_a = this.resolve) === null || _a === void 0 ? void 0 : _a.call(this, latest);\n }\n else if (this.playState !== \"idle\") {\n this.frameRequestId = requestAnimationFrame(this.tick);\n }\n };\n this.play();\n }\n play() {\n const now = performance.now();\n this.playState = \"running\";\n if (this.pauseTime !== undefined) {\n this.startTime = now - this.pauseTime;\n }\n else if (!this.startTime) {\n this.startTime = now;\n }\n this.cancelTimestamp = this.startTime;\n this.pauseTime = undefined;\n this.frameRequestId = requestAnimationFrame(this.tick);\n }\n pause() {\n this.playState = \"paused\";\n this.pauseTime = this.t;\n }\n finish() {\n this.playState = \"finished\";\n this.tick(0);\n }\n stop() {\n var _a;\n this.playState = \"idle\";\n if (this.frameRequestId !== undefined) {\n cancelAnimationFrame(this.frameRequestId);\n }\n (_a = this.reject) === null || _a === void 0 ? void 0 : _a.call(this, false);\n }\n cancel() {\n this.stop();\n this.tick(this.cancelTimestamp);\n }\n reverse() {\n this.rate *= -1;\n }\n commitStyles() { }\n updateDuration(duration) {\n this.duration = duration;\n this.totalDuration = duration * (this.repeat + 1);\n }\n get currentTime() {\n return this.t;\n }\n set currentTime(t) {\n if (this.pauseTime !== undefined || this.rate === 0) {\n this.pauseTime = t;\n }\n else {\n this.startTime = performance.now() - t / this.rate;\n }\n }\n get playbackRate() {\n return this.rate;\n }\n set playbackRate(rate) {\n this.rate = rate;\n }\n}\n\nexport { Animation };\n","var warning = function () { };\r\nvar invariant = function () { };\r\nif (process.env.NODE_ENV !== 'production') {\r\n warning = function (check, message) {\r\n if (!check && typeof console !== 'undefined') {\r\n console.warn(message);\r\n }\r\n };\r\n invariant = function (check, message) {\r\n if (!check) {\r\n throw new Error(message);\r\n }\r\n };\r\n}\n\nexport { invariant, warning };\n","/**\n * The MotionValue tracks the state of a single animatable\n * value. Currently, updatedAt and current are unused. The\n * long term idea is to use this to minimise the number\n * of DOM reads, and to abstract the DOM interactions here.\n */\nclass MotionValue {\n setAnimation(animation) {\n this.animation = animation;\n animation === null || animation === void 0 ? void 0 : animation.finished.then(() => this.clearAnimation()).catch(() => { });\n }\n clearAnimation() {\n this.animation = this.generator = undefined;\n }\n}\n\nexport { MotionValue };\n","import { MotionValue } from '@motionone/types';\n\nconst data = new WeakMap();\nfunction getAnimationData(element) {\n if (!data.has(element)) {\n data.set(element, {\n transforms: [],\n values: new Map(),\n });\n }\n return data.get(element);\n}\nfunction getMotionValue(motionValues, name) {\n if (!motionValues.has(name)) {\n motionValues.set(name, new MotionValue());\n }\n return motionValues.get(name);\n}\n\nexport { getAnimationData, getMotionValue };\n","import { noopReturn, addUniqueItem } from '@motionone/utils';\nimport { getAnimationData } from '../data.es.js';\n\n/**\n * A list of all transformable axes. We'll use this list to generated a version\n * of each axes for each transform.\n */\nconst axes = [\"\", \"X\", \"Y\", \"Z\"];\n/**\n * An ordered array of each transformable value. By default, transform values\n * will be sorted to this order.\n */\nconst order = [\"translate\", \"scale\", \"rotate\", \"skew\"];\nconst transformAlias = {\n x: \"translateX\",\n y: \"translateY\",\n z: \"translateZ\",\n};\nconst rotation = {\n syntax: \"\",\n initialValue: \"0deg\",\n toDefaultUnit: (v) => v + \"deg\",\n};\nconst baseTransformProperties = {\n translate: {\n syntax: \"\",\n initialValue: \"0px\",\n toDefaultUnit: (v) => v + \"px\",\n },\n rotate: rotation,\n scale: {\n syntax: \"\",\n initialValue: 1,\n toDefaultUnit: noopReturn,\n },\n skew: rotation,\n};\nconst transformDefinitions = new Map();\nconst asTransformCssVar = (name) => `--motion-${name}`;\n/**\n * Generate a list of every possible transform key\n */\nconst transforms = [\"x\", \"y\", \"z\"];\norder.forEach((name) => {\n axes.forEach((axis) => {\n transforms.push(name + axis);\n transformDefinitions.set(asTransformCssVar(name + axis), baseTransformProperties[name]);\n });\n});\n/**\n * A function to use with Array.sort to sort transform keys by their default order.\n */\nconst compareTransformOrder = (a, b) => transforms.indexOf(a) - transforms.indexOf(b);\n/**\n * Provide a quick way to check if a string is the name of a transform\n */\nconst transformLookup = new Set(transforms);\nconst isTransform = (name) => transformLookup.has(name);\nconst addTransformToElement = (element, name) => {\n // Map x to translateX etc\n if (transformAlias[name])\n name = transformAlias[name];\n const { transforms } = getAnimationData(element);\n addUniqueItem(transforms, name);\n /**\n * TODO: An optimisation here could be to cache the transform in element data\n * and only update if this has changed.\n */\n element.style.transform = buildTransformTemplate(transforms);\n};\nconst buildTransformTemplate = (transforms) => transforms\n .sort(compareTransformOrder)\n .reduce(transformListToString, \"\")\n .trim();\nconst transformListToString = (template, name) => `${template} ${name}(var(${asTransformCssVar(name)}))`;\n\nexport { addTransformToElement, asTransformCssVar, axes, buildTransformTemplate, compareTransformOrder, isTransform, transformAlias, transformDefinitions };\n","import { transformDefinitions } from './transforms.es.js';\n\nconst isCssVar = (name) => name.startsWith(\"--\");\nconst registeredProperties = new Set();\nfunction registerCssVariable(name) {\n if (registeredProperties.has(name))\n return;\n registeredProperties.add(name);\n try {\n const { syntax, initialValue } = transformDefinitions.has(name)\n ? transformDefinitions.get(name)\n : {};\n CSS.registerProperty({\n name,\n inherits: false,\n syntax,\n initialValue,\n });\n }\n catch (e) { }\n}\n\nexport { isCssVar, registerCssVariable, registeredProperties };\n","const testAnimation = (keyframes, options) => document.createElement(\"div\").animate(keyframes, options);\nconst featureTests = {\n cssRegisterProperty: () => typeof CSS !== \"undefined\" &&\n Object.hasOwnProperty.call(CSS, \"registerProperty\"),\n waapi: () => Object.hasOwnProperty.call(Element.prototype, \"animate\"),\n partialKeyframes: () => {\n try {\n testAnimation({ opacity: [1] });\n }\n catch (e) {\n return false;\n }\n return true;\n },\n finished: () => Boolean(testAnimation({ opacity: [0, 1] }, { duration: 0.001 }).finished),\n linearEasing: () => {\n try {\n testAnimation({ opacity: 0 }, { easing: \"linear(0, 1)\" });\n }\n catch (e) {\n return false;\n }\n return true;\n },\n};\nconst results = {};\nconst supports = {};\nfor (const key in featureTests) {\n supports[key] = () => {\n if (results[key] === undefined)\n results[key] = featureTests[key]();\n return results[key];\n };\n}\n\nexport { supports };\n","import { isFunction, defaults, isCubicBezier, progress } from '@motionone/utils';\nimport { supports } from './feature-detection.es.js';\n\n// Create a linear easing point for every x second\nconst resolution = 0.015;\nconst generateLinearEasingPoints = (easing, duration) => {\n let points = \"\";\n const numPoints = Math.round(duration / resolution);\n for (let i = 0; i < numPoints; i++) {\n points += easing(progress(0, numPoints - 1, i)) + \", \";\n }\n return points.substring(0, points.length - 2);\n};\nconst convertEasing = (easing, duration) => {\n if (isFunction(easing)) {\n return supports.linearEasing()\n ? `linear(${generateLinearEasingPoints(easing, duration)})`\n : defaults.easing;\n }\n else {\n return isCubicBezier(easing) ? cubicBezierAsString(easing) : easing;\n }\n};\nconst cubicBezierAsString = ([a, b, c, d]) => `cubic-bezier(${a}, ${b}, ${c}, ${d})`;\n\nexport { convertEasing, cubicBezierAsString, generateLinearEasingPoints };\n","function hydrateKeyframes(keyframes, readInitialValue) {\n for (let i = 0; i < keyframes.length; i++) {\n if (keyframes[i] === null) {\n keyframes[i] = i ? keyframes[i - 1] : readInitialValue();\n }\n }\n return keyframes;\n}\nconst keyframesList = (keyframes) => Array.isArray(keyframes) ? keyframes : [keyframes];\n\nexport { hydrateKeyframes, keyframesList };\n","import { isTransform, asTransformCssVar, transformAlias } from './transforms.es.js';\n\nfunction getStyleName(key) {\n if (transformAlias[key])\n key = transformAlias[key];\n return isTransform(key) ? asTransformCssVar(key) : key;\n}\n\nexport { getStyleName };\n","import { isCssVar } from './utils/css-var.es.js';\nimport { getStyleName } from './utils/get-style-name.es.js';\nimport { transformDefinitions } from './utils/transforms.es.js';\n\nconst style = {\n get: (element, name) => {\n name = getStyleName(name);\n let value = isCssVar(name)\n ? element.style.getPropertyValue(name)\n : getComputedStyle(element)[name];\n if (!value && value !== 0) {\n const definition = transformDefinitions.get(name);\n if (definition)\n value = definition.initialValue;\n }\n return value;\n },\n set: (element, name, value) => {\n name = getStyleName(name);\n if (isCssVar(name)) {\n element.style.setProperty(name, value);\n }\n else {\n element.style[name] = value;\n }\n },\n};\n\nexport { style };\n","function stopAnimation(animation, needsCommit = true) {\n if (!animation || animation.playState === \"finished\")\n return;\n // Suppress error thrown by WAAPI\n try {\n if (animation.stop) {\n animation.stop();\n }\n else {\n needsCommit && animation.commitStyles();\n animation.cancel();\n }\n }\n catch (e) { }\n}\n\nexport { stopAnimation };\n","import { noopReturn, isString } from '@motionone/utils';\n\nfunction getUnitConverter(keyframes, definition) {\n var _a;\n let toUnit = (definition === null || definition === void 0 ? void 0 : definition.toDefaultUnit) || noopReturn;\n const finalKeyframe = keyframes[keyframes.length - 1];\n if (isString(finalKeyframe)) {\n const unit = ((_a = finalKeyframe.match(/(-?[\\d.]+)([a-z%]*)/)) === null || _a === void 0 ? void 0 : _a[2]) || \"\";\n if (unit)\n toUnit = (value) => value + unit;\n }\n return toUnit;\n}\n\nexport { getUnitConverter };\n","import { getAnimationData, getMotionValue } from './data.es.js';\nimport { isCssVar, registerCssVariable } from './utils/css-var.es.js';\nimport { defaults, isEasingGenerator, isFunction, isEasingList, isNumber, time, noop } from '@motionone/utils';\nimport { isTransform, addTransformToElement, transformDefinitions } from './utils/transforms.es.js';\nimport { convertEasing } from './utils/easing.es.js';\nimport { supports } from './utils/feature-detection.es.js';\nimport { hydrateKeyframes, keyframesList } from './utils/keyframes.es.js';\nimport { style } from './style.es.js';\nimport { getStyleName } from './utils/get-style-name.es.js';\nimport { stopAnimation } from './utils/stop-animation.es.js';\nimport { getUnitConverter } from './utils/get-unit.es.js';\n\nfunction getDevToolsRecord() {\n return window.__MOTION_DEV_TOOLS_RECORD;\n}\nfunction animateStyle(element, key, keyframesDefinition, options = {}, AnimationPolyfill) {\n const record = getDevToolsRecord();\n const isRecording = options.record !== false && record;\n let animation;\n let { duration = defaults.duration, delay = defaults.delay, endDelay = defaults.endDelay, repeat = defaults.repeat, easing = defaults.easing, persist = false, direction, offset, allowWebkitAcceleration = false, } = options;\n const data = getAnimationData(element);\n const valueIsTransform = isTransform(key);\n let canAnimateNatively = supports.waapi();\n /**\n * If this is an individual transform, we need to map its\n * key to a CSS variable and update the element's transform style\n */\n valueIsTransform && addTransformToElement(element, key);\n const name = getStyleName(key);\n const motionValue = getMotionValue(data.values, name);\n /**\n * Get definition of value, this will be used to convert numerical\n * keyframes into the default value type.\n */\n const definition = transformDefinitions.get(name);\n /**\n * Stop the current animation, if any. Because this will trigger\n * commitStyles (DOM writes) and we might later trigger DOM reads,\n * this is fired now and we return a factory function to create\n * the actual animation that can get called in batch,\n */\n stopAnimation(motionValue.animation, !(isEasingGenerator(easing) && motionValue.generator) &&\n options.record !== false);\n /**\n * Batchable factory function containing all DOM reads.\n */\n return () => {\n const readInitialValue = () => { var _a, _b; return (_b = (_a = style.get(element, name)) !== null && _a !== void 0 ? _a : definition === null || definition === void 0 ? void 0 : definition.initialValue) !== null && _b !== void 0 ? _b : 0; };\n /**\n * Replace null values with the previous keyframe value, or read\n * it from the DOM if it's the first keyframe.\n */\n let keyframes = hydrateKeyframes(keyframesList(keyframesDefinition), readInitialValue);\n /**\n * Detect unit type of keyframes.\n */\n const toUnit = getUnitConverter(keyframes, definition);\n if (isEasingGenerator(easing)) {\n const custom = easing.createAnimation(keyframes, key !== \"opacity\", readInitialValue, name, motionValue);\n easing = custom.easing;\n keyframes = custom.keyframes || keyframes;\n duration = custom.duration || duration;\n }\n /**\n * If this is a CSS variable we need to register it with the browser\n * before it can be animated natively. We also set it with setProperty\n * rather than directly onto the element.style object.\n */\n if (isCssVar(name)) {\n if (supports.cssRegisterProperty()) {\n registerCssVariable(name);\n }\n else {\n canAnimateNatively = false;\n }\n }\n /**\n * If we've been passed a custom easing function, and this browser\n * does **not** support linear() easing, and the value is a transform\n * (and thus a pure number) we can still support the custom easing\n * by falling back to the animation polyfill.\n */\n if (valueIsTransform &&\n !supports.linearEasing() &&\n (isFunction(easing) || (isEasingList(easing) && easing.some(isFunction)))) {\n canAnimateNatively = false;\n }\n /**\n * If we can animate this value with WAAPI, do so.\n */\n if (canAnimateNatively) {\n /**\n * Convert numbers to default value types. Currently this only supports\n * transforms but it could also support other value types.\n */\n if (definition) {\n keyframes = keyframes.map((value) => isNumber(value) ? definition.toDefaultUnit(value) : value);\n }\n /**\n * If this browser doesn't support partial/implicit keyframes we need to\n * explicitly provide one.\n */\n if (keyframes.length === 1 &&\n (!supports.partialKeyframes() || isRecording)) {\n keyframes.unshift(readInitialValue());\n }\n const animationOptions = {\n delay: time.ms(delay),\n duration: time.ms(duration),\n endDelay: time.ms(endDelay),\n easing: !isEasingList(easing)\n ? convertEasing(easing, duration)\n : undefined,\n direction,\n iterations: repeat + 1,\n fill: \"both\",\n };\n animation = element.animate({\n [name]: keyframes,\n offset,\n easing: isEasingList(easing)\n ? easing.map((thisEasing) => convertEasing(thisEasing, duration))\n : undefined,\n }, animationOptions);\n /**\n * Polyfill finished Promise in browsers that don't support it\n */\n if (!animation.finished) {\n animation.finished = new Promise((resolve, reject) => {\n animation.onfinish = resolve;\n animation.oncancel = reject;\n });\n }\n const target = keyframes[keyframes.length - 1];\n animation.finished\n .then(() => {\n if (persist)\n return;\n // Apply styles to target\n style.set(element, name, target);\n // Ensure fill modes don't persist\n animation.cancel();\n })\n .catch(noop);\n /**\n * This forces Webkit to run animations on the main thread by exploiting\n * this condition:\n * https://trac.webkit.org/browser/webkit/trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp?rev=281238#L1099\n *\n * This fixes Webkit's timing bugs, like accelerated animations falling\n * out of sync with main thread animations and massive delays in starting\n * accelerated animations in WKWebView.\n */\n if (!allowWebkitAcceleration)\n animation.playbackRate = 1.000001;\n /**\n * If we can't animate the value natively then we can fallback to the numbers-only\n * polyfill for transforms.\n */\n }\n else if (AnimationPolyfill && valueIsTransform) {\n /**\n * If any keyframe is a string (because we measured it from the DOM), we need to convert\n * it into a number before passing to the Animation polyfill.\n */\n keyframes = keyframes.map((value) => typeof value === \"string\" ? parseFloat(value) : value);\n /**\n * If we only have a single keyframe, we need to create an initial keyframe by reading\n * the current value from the DOM.\n */\n if (keyframes.length === 1) {\n keyframes.unshift(parseFloat(readInitialValue()));\n }\n animation = new AnimationPolyfill((latest) => {\n style.set(element, name, toUnit ? toUnit(latest) : latest);\n }, keyframes, Object.assign(Object.assign({}, options), { duration,\n easing }));\n }\n else {\n const target = keyframes[keyframes.length - 1];\n style.set(element, name, definition && isNumber(target)\n ? definition.toDefaultUnit(target)\n : target);\n }\n if (isRecording) {\n record(element, key, keyframes, {\n duration,\n delay: delay,\n easing,\n repeat,\n offset,\n }, \"motion-one\");\n }\n motionValue.setAnimation(animation);\n return animation;\n };\n}\n\nexport { animateStyle };\n","const getOptions = (options, key) => \n/**\n * TODO: Make test for this\n * Always return a new object otherwise delay is overwritten by results of stagger\n * and this results in no stagger\n */\noptions[key] ? Object.assign(Object.assign({}, options), options[key]) : Object.assign({}, options);\n\nexport { getOptions };\n","function resolveElements(elements, selectorCache) {\n var _a;\n if (typeof elements === \"string\") {\n if (selectorCache) {\n (_a = selectorCache[elements]) !== null && _a !== void 0 ? _a : (selectorCache[elements] = document.querySelectorAll(elements));\n elements = selectorCache[elements];\n }\n else {\n elements = document.querySelectorAll(elements);\n }\n }\n else if (elements instanceof Element) {\n elements = [elements];\n }\n /**\n * Return an empty array\n */\n return Array.from(elements || []);\n}\n\nexport { resolveElements };\n","import { defaults, noop, time } from '@motionone/utils';\nimport { stopAnimation } from './stop-animation.es.js';\n\nconst createAnimation = (factory) => factory();\nconst withControls = (animationFactory, options, duration = defaults.duration) => {\n return new Proxy({\n animations: animationFactory.map(createAnimation).filter(Boolean),\n duration,\n options,\n }, controls);\n};\n/**\n * TODO:\n * Currently this returns the first animation, ideally it would return\n * the first active animation.\n */\nconst getActiveAnimation = (state) => state.animations[0];\nconst controls = {\n get: (target, key) => {\n const activeAnimation = getActiveAnimation(target);\n switch (key) {\n case \"duration\":\n return target.duration;\n case \"currentTime\":\n return time.s((activeAnimation === null || activeAnimation === void 0 ? void 0 : activeAnimation[key]) || 0);\n case \"playbackRate\":\n case \"playState\":\n return activeAnimation === null || activeAnimation === void 0 ? void 0 : activeAnimation[key];\n case \"finished\":\n if (!target.finished) {\n target.finished = Promise.all(target.animations.map(selectFinished)).catch(noop);\n }\n return target.finished;\n case \"stop\":\n return () => {\n target.animations.forEach((animation) => stopAnimation(animation));\n };\n case \"forEachNative\":\n /**\n * This is for internal use only, fire a callback for each\n * underlying animation.\n */\n return (callback) => {\n target.animations.forEach((animation) => callback(animation, target));\n };\n default:\n return typeof (activeAnimation === null || activeAnimation === void 0 ? void 0 : activeAnimation[key]) === \"undefined\"\n ? undefined\n : () => target.animations.forEach((animation) => animation[key]());\n }\n },\n set: (target, key, value) => {\n switch (key) {\n case \"currentTime\":\n value = time.ms(value);\n // Fall-through\n case \"playbackRate\":\n for (let i = 0; i < target.animations.length; i++) {\n target.animations[i][key] = value;\n }\n return true;\n }\n return false;\n },\n};\nconst selectFinished = (animation) => animation.finished;\n\nexport { controls, withControls };\n","import { isNumber, isFunction } from '@motionone/utils';\nimport { getEasingFunction } from '@motionone/animation';\n\nfunction stagger(duration = 0.1, { start = 0, from = 0, easing } = {}) {\n return (i, total) => {\n const fromIndex = isNumber(from) ? from : getFromIndex(from, total);\n const distance = Math.abs(fromIndex - i);\n let delay = duration * distance;\n if (easing) {\n const maxDelay = total * duration;\n const easingFunction = getEasingFunction(easing);\n delay = easingFunction(delay / maxDelay) * maxDelay;\n }\n return start + delay;\n };\n}\nfunction getFromIndex(from, total) {\n if (from === \"first\") {\n return 0;\n }\n else {\n const lastIndex = total - 1;\n return from === \"last\" ? lastIndex : lastIndex / 2;\n }\n}\nfunction resolveOption(option, i, total) {\n return isFunction(option) ? option(i, total) : option;\n}\n\nexport { getFromIndex, resolveOption, stagger };\n","import { invariant } from 'hey-listen';\nimport { animateStyle } from './animate-style.es.js';\nimport { getOptions } from './utils/options.es.js';\nimport { resolveElements } from '../utils/resolve-elements.es.js';\nimport { withControls } from './utils/controls.es.js';\nimport { resolveOption } from '../utils/stagger.es.js';\n\nfunction createAnimate(AnimatePolyfill) {\n return function animate(elements, keyframes, options = {}) {\n elements = resolveElements(elements);\n const numElements = elements.length;\n invariant(Boolean(numElements), \"No valid element provided.\");\n invariant(Boolean(keyframes), \"No keyframes defined.\");\n /**\n * Create and start new animations\n */\n const animationFactories = [];\n for (let i = 0; i < numElements; i++) {\n const element = elements[i];\n for (const key in keyframes) {\n const valueOptions = getOptions(options, key);\n valueOptions.delay = resolveOption(valueOptions.delay, i, numElements);\n const animation = animateStyle(element, key, keyframes[key], valueOptions, AnimatePolyfill);\n animationFactories.push(animation);\n }\n }\n return withControls(animationFactories, options, \n /**\n * TODO:\n * If easing is set to spring or glide, duration will be dynamically\n * generated. Ideally we would dynamically generate this from\n * animation.effect.getComputedTiming().duration but this isn't\n * supported in iOS13 or our number polyfill. Perhaps it's possible\n * to Proxy animations returned from animateStyle that has duration\n * as a getter.\n */\n options.duration);\n };\n}\n\nexport { createAnimate };\n","import { Animation } from '@motionone/animation';\nimport { createAnimate } from './create-animate.es.js';\n\nconst animate = createAnimate(Animation);\n\nexport { animate };\n","import { animate as animate$1, withControls } from '@motionone/dom';\nimport { isFunction } from '@motionone/utils';\nimport { Animation } from '@motionone/animation';\n\nfunction animateProgress(target, options = {}) {\n return withControls([\n () => {\n const animation = new Animation(target, [0, 1], options);\n animation.finished.catch(() => { });\n return animation;\n },\n ], options, options.duration);\n}\nfunction animate(target, keyframesOrOptions, options) {\n const factory = isFunction(target) ? animateProgress : animate$1;\n return factory(target, keyframesOrOptions, options);\n}\n\nexport { animate, animateProgress };\n","import { clamp } from 'lodash-es';\nimport { animate } from 'motion';\nimport { UAParser } from 'ua-parser-js';\nimport { BUILD_CONFIG, BuildConfig, Platform, detectEnv } from '../assets/src/BuildConfig';\nimport { Result } from '../assets/src/utils/Result';\nimport { getObjectKeys } from '../assets/src/utils/collection/get-object-keys';\nimport { isDesktop } from '../assets/src/utils/device/is-desktop';\nimport { DEBUG_STORE } from '../assets/src/utils/local-storage-utils';\nimport { detectPlatform } from '../assets/src/utils/platform/platform';\nimport { CrazyGamesPlatformPreloader } from './platform/CrazyGamesPlatformPreloader';\nimport { FbPlatformPreloader } from './platform/FbPlatformPreloader';\nimport { IPlatformPreloader } from './platform/IPlatformPreloader';\nimport { VkPlatformPreloader } from './platform/VkPlatformPreloader';\nimport { YaPlatformPreloader } from './platform/YaPlatformPreloader';\n\nconst LOADING_STAGES = {\n\t'cocos-initial': 20,\n\t'preloader-onload': 30,\n\t'device-features': 33,\n\t'auth': 35,\n\t'state': 40,\n\t'platform': 45,\n\t'resources': 50,\n\t'time-manager-ready': 65,\n\t'globalScene': 80,\n\t'gameScene': 100,\n} as const;\n\nexport type LoadingStage = keyof typeof LOADING_STAGES;\n\ntype HideOptions = { instant: true } | { instant: false; duration?: number };\n\nexport class Preloader {\n\tprivate preloaderClicksNum = 0;\n\tprivate preloaderContainer: HTMLDivElement;\n\tprivate loadingText: HTMLDivElement;\n\tprivate loadingBar: HTMLSpanElement;\n\n\tprivate isLoadComplete = false;\n\tprivate totalProgress = 0;\n\tprivate currentStage: LoadingStage = 'cocos-initial';\n\tprivate currentStageProgress = 0;\n\tprivate intervalId: number;\n\tprivate loadComplete = new AbortController();\n\n\tprivate readonly _platformPreloader: IPlatformPreloader | undefined;\n\n\tconstructor() {\n\t\tthis.trackPageVisibility(this.loadComplete.signal);\n\n\t\tif (DEBUG_STORE.get('clearConsoleOnStart') === '1') {\n\t\t\tconsole.clear();\n\t\t}\n\n\t\t// @ts-expect-error\n\t\twindow['userAgent'] = new UAParser();\n\n\t\tBUILD_CONFIG.platform = detectPlatform();\n\t\tBUILD_CONFIG.env = detectEnv(location.hostname, BUILD_CONFIG.platform);\n\n\t\tconst cocosToolbar = document.querySelector('.toolbar');\n\t\tif (cocosToolbar) {\n\t\t\t// скрываем тулбар от Cocos\n\t\t\tcocosToolbar.style.display = 'none';\n\t\t}\n\n\t\tif (BUILD_CONFIG.env === 'personal') {\n\t\t\tthis.preventVConsole();\n\t\t}\n\n\t\tthis.preloaderContainer = document.getElementById('preloader-container') as HTMLDivElement;\n\t\tthis.loadingText = document.getElementById('loading-progress-text') as HTMLDivElement;\n\t\tthis.loadingBar = document.getElementById('preloader-bar') as HTMLDivElement;\n\n\t\tthis.adjustPreloaderGameLogo();\n\n\t\tif (userAgent.getOS().name === 'iOS' || userAgent.getBrowser().name === 'Safari') {\n\t\t\tdocument.getElementById('progressbarFrame').style.display = 'none';\n\t\t}\n\n\t\tthis.addConsoleErrorHook();\n\n\t\tthis.adjustScaling();\n\n\t\tthis.initBuildInfoText(BUILD_CONFIG);\n\n\t\tthis.updateTotalProgress(0);\n\t\tthis.startStage('cocos-initial');\n\t\tthis.startFakeProgress();\n\n\t\tif (BUILD_CONFIG.env !== 'production') {\n\t\t\tthis.preloaderContainer.addEventListener('pointerdown', this.onPreloaderClick.bind(this));\n\t\t}\n\n\t\tthis._platformPreloader = this.createPlatformPreloader(BUILD_CONFIG.platform);\n\t\tif (this._platformPreloader) {\n\t\t\tthis._platformPreloader.loadAndInit().then((result: Result) => {\n\t\t\t\tthis.adjustPreloaderGameLogo();\n\t\t\t\tconsole.log(`platform preloader load with result`, result);\n\t\t\t});\n\t\t}\n\t}\n\n\t// отслеживаем теряла ли вкладка с игрой фокус во время загрузки, эта информация будет использована позже в аналитике\n\tprivate trackPageVisibility(abortSignal: AbortSignal): void {\n\t\tif (document.visibilityState === 'hidden') {\n\t\t\tthis.onPageHidden();\n\t\t\treturn;\n\t\t}\n\n\t\tdocument.addEventListener('visibilitychange', this.onVisibilityChange.bind(this), {\n\t\t\tsignal: abortSignal,\n\t\t});\n\t}\n\n\tprivate onVisibilityChange(): void {\n\t\tif (document.visibilityState === 'hidden') {\n\t\t\tthis.onPageHidden();\n\t\t}\n\t}\n\n\tprivate onPageHidden(): void {\n\t\tDEBUG_STORE.set('loadPageWasHidden', '1');\n\t}\n\n\tprivate adjustPreloaderGameLogo(): void {\n\t\tconst logo = document.getElementById('preloader-logo');\n\t\tif (!logo) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (BUILD_CONFIG.platform === 'fbInstant' || BUILD_CONFIG.platform === 'cg') {\n\t\t\tlogo.classList.add('preloader-logo-en');\n\t\t} else if (BUILD_CONFIG.platform === 'ya') {\n\t\t\tif ('yandexGames' in window) {\n\t\t\t\t// после того как yandex sdk инициализировано мы можем получить локаль игрока и отобразить соответствующее лого\n\t\t\t\tconst lang = yandexGames.environment.i18n.lang;\n\t\t\t\tconsole.log(`yandex language: ${lang}`);\n\t\t\t\tlogo.classList.remove('preloader-logo-hidden');\n\t\t\t\tlogo.classList.add(lang === 'ru' ? 'preloader-logo-ru' : 'preloader-logo-en');\n\t\t\t} else {\n\t\t\t\tlogo.classList.add('preloader-logo-hidden');\n\t\t\t}\n\t\t} else {\n\t\t\tlogo.classList.add('preloader-logo-ru');\n\t\t}\n\t}\n\n\tpublic get platformPreloader(): IPlatformPreloader | undefined {\n\t\treturn this._platformPreloader;\n\t}\n\n\tprivate createPlatformPreloader(platform: Platform): IPlatformPreloader {\n\t\tswitch (platform) {\n\t\t\tcase 'vk':\n\t\t\t\treturn new VkPlatformPreloader();\n\t\t\tcase 'fbInstant':\n\t\t\t\treturn new FbPlatformPreloader();\n\t\t\tcase 'ya':\n\t\t\t\treturn new YaPlatformPreloader();\n\t\t\tcase 'cg':\n\t\t\t\treturn new CrazyGamesPlatformPreloader();\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprivate preventVConsole(): void {\n\t\tlet removedNodesCount = 0;\n\n\t\tconst nodeRemoveCallback = (node: ChildNode) => {\n\t\t\tnode.remove();\n\t\t\tif (++removedNodesCount === 3) {\n\t\t\t\tobserver.disconnect();\n\t\t\t}\n\t\t};\n\n\t\tconst observer = new MutationObserver((mutations, observer) => {\n\t\t\tmutations.forEach((mut) => {\n\t\t\t\tmut.addedNodes.forEach((node) => {\n\t\t\t\t\tif (node instanceof Comment && node.textContent.includes('v-console')) {\n\t\t\t\t\t\tnodeRemoveCallback(node);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (node instanceof HTMLScriptElement) {\n\t\t\t\t\t\tif (node.src.includes('vconsole') || node.innerText.includes('VConsole')) {\n\t\t\t\t\t\t\tnodeRemoveCallback(node);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\n\t\tobserver.observe(document.body, { childList: true });\n\t}\n\n\tprivate onPreloaderClick(): void {\n\t\tif (++this.preloaderClicksNum >= 3) {\n\t\t\tthis.preloaderClicksNum = 0;\n\n\t\t\t// на ФБ запрещены модальные окна (confirm, alert, etc.)\n\t\t\tconst clearProfile = BUILD_CONFIG.platform === 'fbInstant' ? true : confirm('Очистить профиль?');\n\t\t\tif (clearProfile) {\n\t\t\t\tDEBUG_STORE.set('profile_clear_pending', '1');\n\t\t\t\tlocation.reload();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate addConsoleErrorHook(): void {\n\t\tconst originalConsoleError = console.error.bind(console);\n\t\tconsole.error = (...args: any[]) => {\n\t\t\t'consoleErrorPreHook' in window && window.consoleErrorPreHook?.call(null, ...args);\n\t\t\toriginalConsoleError(...args);\n\t\t};\n\t}\n\n\tprivate adjustScaling(): void {\n\t\tif (isDesktop()) {\n\t\t\treturn;\n\t\t}\n\n\t\t// make preloader fill the whole page for mobile devices\n\t\tthis.preloaderContainer.style.width = '100%';\n\t\tthis.preloaderContainer.style.removeProperty('aspect-ratio');\n\t}\n\n\tprivate initBuildInfoText(buildConfig: BuildConfig): void {\n\t\tconst buildInfo = document.getElementById('build-info');\n\t\tif (!buildInfo) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst env = buildConfig.env;\n\t\tif (env === 'personal') {\n\t\t\treturn;\n\t\t}\n\n\t\tconst { buildNumber, buildDate } = buildConfig;\n\t\tconst prefix = env === 'production' ? `v${buildNumber}` : `${env}-${buildNumber}`;\n\t\tbuildInfo.innerText = `${prefix} (${buildDate})`;\n\t}\n\n\tpublic startFakeProgress(): void {\n\t\tif (typeof this.intervalId === 'number') {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.intervalId = setInterval(this.fakeProgressUpdate.bind(this), 200);\n\t}\n\n\tpublic stopFakeProgress(): void {\n\t\tif (typeof this.intervalId === 'number') {\n\t\t\tclearInterval(this.intervalId);\n\t\t\tthis.intervalId = undefined;\n\t\t}\n\t}\n\n\tprivate fakeProgressUpdate(): void {\n\t\tthis.currentStageProgress += 1;\n\t\tthis.updateTotalProgress(this.calculateTotalProgress());\n\t}\n\n\tpublic startStage(stage: LoadingStage): void {\n\t\tthis.currentStage = stage;\n\t\tthis.currentStageProgress = 0;\n\t\tthis.updateTotalProgress(this.calculateTotalProgress());\n\t}\n\n\tprivate calculateTotalProgress(): number {\n\t\tconst [start, end] = this.getStageSpan(this.currentStage);\n\t\tconst adjustedProgress = Math.min(1, this.currentStageProgress / 100);\n\t\treturn Math.round(start + adjustedProgress * (end - start));\n\t}\n\n\tprivate getStageSpan(stage: LoadingStage): [start: number, end: number] {\n\t\tconst allStages = getObjectKeys(LOADING_STAGES);\n\t\tconst stageIndex = allStages.indexOf(stage);\n\t\tconst start = stageIndex === 0 ? 0 : LOADING_STAGES[allStages[stageIndex - 1]];\n\t\tconst end = LOADING_STAGES[stage];\n\t\treturn [start, end];\n\t}\n\n\tpublic updateTotalProgress(value: number): void {\n\t\tconst progressMaxValue = this.isLoadComplete ? 100 : 99;\n\t\tthis.totalProgress = clamp(Math.round(value), 0, progressMaxValue);\n\t\tthis.loadingText.textContent = this.getLoadingTextContent(this.totalProgress);\n\t\tthis.loadingBar.style.width = `${this.totalProgress}%`;\n\t\tthis._platformPreloader?.setLoadingProgress(this.totalProgress);\n\t}\n\n\tprivate getLoadingTextContent(progress: number): string {\n\t\tconst platform = BUILD_CONFIG.platform;\n\t\tif (platform === 'ya') {\n\t\t\treturn progress + '%';\n\t\t}\n\n\t\tconst prefix = platform === 'fbInstant' || platform === 'cg' ? 'Loading' : 'Загрузка';\n\t\treturn `${prefix}: ${progress}%`;\n\t}\n\n\tpublic async complete(options: HideOptions) {\n\t\tthis.stopFakeProgress();\n\t\tthis.loadComplete.abort();\n\t\tthis.isLoadComplete = true;\n\n\t\tif (options.instant === true) {\n\t\t\tthis.updateTotalProgress(100);\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\tconst start = this.totalProgress;\n\t\tconst delta = 100 - start;\n\t\treturn animate(\n\t\t\t(progress) => {\n\t\t\t\tthis.updateTotalProgress(start + delta * progress);\n\t\t\t},\n\t\t\t{ duration: options.duration ?? 0.3 },\n\t\t).finished;\n\t}\n\n\tpublic async hide(options: HideOptions) {\n\t\tif (options.instant === true) {\n\t\t\tthis.preloaderContainer.style.display = 'none';\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\t// `animate()` may fail on old browsers, so we wrap it in try-catch\n\t\t\tanimate(\n\t\t\t\tthis.preloaderContainer,\n\t\t\t\t{ opacity: 0 },\n\t\t\t\t{\n\t\t\t\t\tduration: options.duration ?? 0.3,\n\t\t\t\t\tdelay: 0.25,\n\t\t\t\t\teasing: 'ease-out',\n\t\t\t\t},\n\t\t\t).finished.finally(() => {\n\t\t\t\tthis.preloaderContainer.style.display = 'none';\n\t\t\t});\n\t\t} catch (e) {\n\t\t\tthis.preloaderContainer.style.display = 'none';\n\t\t}\n\t}\n\n\tpublic get isVisible(): boolean {\n\t\treturn this.preloaderContainer.style.display !== 'none';\n\t}\n}\n\n// @ts-expect-error\nwindow['preloader'] = new Preloader();\n","/**\n * Шаблон конфига\n * Автоматически дописывается данными из конфига при сборке проекта\n * Локально можно менять, коммитить следует только как шаблон внутри utils/build-configs-params-transfer\n * В конец файла будет дописан следующий код\n * export const BUILD_CONFIG: BuildConfig = {};\n * где внутри будет указан конфиг\n */\n\nexport type Runtime = 'web' | 'ios' | 'android';\n\nexport type Platform = 'vk' | 'ok' | 'fbInstant' | 'ya' | 'cg' | 'none';\n\nexport type Environment = 'personal' | 'develop' | 'stable' | 'master' | 'production';\n\nexport type BuildType = 'preview' | 'release';\n\nexport interface BuildConfig {\n\truntime: Runtime;\n\tplatform: Platform;\n\tenv: Environment;\n\ttype: BuildType;\n\treadonly buildNumber: number;\n\treadonly buildDate: string;\n\treadonly cocosCreatorVersion: string;\n\treadonly gitCommit: string;\n\treadonly gitBranch: string;\n\t// TODO add vk & ok app ids\n\treadonly apps: {\n\t\t[platform in Exclude]: {\n\t\t\t[env in Environment]: { appId: string; [key: string]: unknown };\n\t\t};\n\t};\n}\n\nexport function detectEnv(hostname: string, platform: Platform): Environment {\n\t// отдельная логика определения env для ФБ, так как ФБ билды хостятся не на наших хостах\n\tif (platform === 'fbInstant') {\n\t\tconst { develop, stable, master, production } = BUILD_CONFIG.apps[platform];\n\n\t\tif (hostname.endsWith(`${develop.appId}.apps.fbsbx.com`)) {\n\t\t\treturn 'develop';\n\t\t} else if (hostname.endsWith(`${stable.appId}.apps.fbsbx.com`)) {\n\t\t\treturn 'stable';\n\t\t} else if (hostname.endsWith(`${master.appId}.apps.fbsbx.com`)) {\n\t\t\treturn 'master';\n\t\t} else if (hostname.endsWith(`${production.appId}.apps.fbsbx.com`)) {\n\t\t\treturn 'production';\n\t\t} else {\n\t\t\treturn 'personal';\n\t\t}\n\t}\n\n\tif (hostname.startsWith('client-develop')) {\n\t\treturn 'develop';\n\t} else if (hostname.startsWith('client-stable')) {\n\t\treturn 'stable';\n\t} else if (hostname.startsWith('client-master')) {\n\t\treturn 'master';\n\t} else if (hostname.startsWith('goblins-static')) {\n\t\treturn 'production';\n\t} else {\n\t\treturn 'personal';\n\t}\n}\n\nexport function envNum(env: Environment) {\n\tswitch (env) {\n\t\tcase 'personal':\n\t\t\treturn 0;\n\t\tcase 'develop':\n\t\t\treturn 1;\n\t\tcase 'stable':\n\t\t\treturn 2;\n\t\tcase 'master':\n\t\t\treturn 3;\n\t\tcase 'production':\n\t\t\treturn 4;\n\n\t\tdefault:\n\t\t\tconst num: never = env;\n\t\t\tthrow new Error(`Unknown environment! [value: ${env}]`);\n\t}\n}\n\nexport function platformTag(platform: Platform) {\n\tswitch (platform) {\n\t\tcase 'vk':\n\t\tcase 'ok':\n\t\tcase 'ya':\n\t\tcase 'cg':\n\t\tcase 'none':\n\t\t\treturn platform;\n\t\tcase 'fbInstant':\n\t\t\treturn 'fb';\n\n\t\tdefault:\n\t\t\tconst tag: never = platform;\n\t\t\tthrow new Error(`Unknown environment! [value: ${platform}]`);\n\t}\n}\n\nexport const BUILD_CONFIG: BuildConfig = {\n\t\"runtime\": \"web\",\n\t\"platform\": \"none\",\n\t\"env\": \"develop\",\n\t\"type\": \"release\",\n\t\"buildNumber\": \"490\",\n\t\"buildDate\": \"2024-10-28 13:33\",\n\t\"cocosCreatorVersion\": \"3.8.4\",\n\t\"gitCommit\": \"f66f8fa26927b7ffb3127f96d973c302b5bd27a5\",\n\t\"gitBranch\": \"master\",\n\t\"apps\": {\n\t\t\"vk\": {\n\t\t\t\"personal\": {\n\t\t\t\t\"appId\": \"51753504\"\n\t\t\t},\n\t\t\t\"develop\": {\n\t\t\t\t\"appId\": \"51676043\"\n\t\t\t},\n\t\t\t\"stable\": {\n\t\t\t\t\"appId\": \"51676049\"\n\t\t\t},\n\t\t\t\"master\": {\n\t\t\t\t\"appId\": \"51676055\"\n\t\t\t},\n\t\t\t\"production\": {\n\t\t\t\t\"appId\": \"51676057\"\n\t\t\t}\n\t\t},\n\t\t\"ok\": {\n\t\t\t\"personal\": {\n\t\t\t\t\"appId\": \"512002048307\"\n\t\t\t},\n\t\t\t\"develop\": {\n\t\t\t\t\"appId\": \"512002075061\"\n\t\t\t},\n\t\t\t\"stable\": {\n\t\t\t\t\"appId\": \"512002025370\"\n\t\t\t},\n\t\t\t\"master\": {\n\t\t\t\t\"appId\": \"512002078099\"\n\t\t\t},\n\t\t\t\"production\": {\n\t\t\t\t\"appId\": \"512001929797\"\n\t\t\t}\n\t\t},\n\t\t\"ya\": {\n\t\t\t\"personal\": {\n\t\t\t\t\"appId\": \"303797\"\n\t\t\t},\n\t\t\t\"develop\": {\n\t\t\t\t\"appId\": \"311149\"\n\t\t\t},\n\t\t\t\"stable\": {\n\t\t\t\t\"appId\": \"311163\"\n\t\t\t},\n\t\t\t\"master\": {\n\t\t\t\t\"appId\": \"311165\"\n\t\t\t},\n\t\t\t\"production\": {\n\t\t\t\t\"appId\": \"311166\"\n\t\t\t}\n\t\t},\n\t\t\"cg\": {\n\t\t\t\"personal\": {\n\t\t\t\t\"appId\": \"061f6e2b-6e4f-4543-aea4-0fffbb6fed54\",\n\t\t\t\t\"xsollaProjectId\": \"270453\"\n\t\t\t},\n\t\t\t\"develop\": {\n\t\t\t\t\"appId\": \"f8819d3f-3db3-4fae-b64d-170635380022\",\n\t\t\t\t\"xsollaProjectId\": \"270453\"\n\t\t\t},\n\t\t\t\"stable\": {\n\t\t\t\t\"appId\": \"6e019297-b57e-4003-8191-5449140693af\",\n\t\t\t\t\"xsollaProjectId\": \"270505\"\n\t\t\t},\n\t\t\t\"master\": {\n\t\t\t\t\"appId\": \"8163673d-4949-4ebd-8cf1-8b9e6a09eced\",\n\t\t\t\t\"xsollaProjectId\": \"270506\"\n\t\t\t},\n\t\t\t\"production\": {\n\t\t\t\t\"appId\": \"5253d818-cf7d-4b86-931b-997cc18db8d4\",\n\t\t\t\t\"xsollaProjectId\": \"270454\"\n\t\t\t}\n\t\t},\n\t\t\"fbInstant\": {\n\t\t\t\"personal\": {\n\t\t\t\t\"appId\": \"1150237969663659\"\n\t\t\t},\n\t\t\t\"develop\": {\n\t\t\t\t\"appId\": \"1150237969663659\"\n\t\t\t},\n\t\t\t\"stable\": {\n\t\t\t\t\"appId\": \"918274610037700\"\n\t\t\t},\n\t\t\t\"master\": {\n\t\t\t\t\"appId\": \"971032394638295\"\n\t\t\t},\n\t\t\t\"production\": {\n\t\t\t\t\"appId\": \"1062414028379441\"\n\t\t\t}\n\t\t}\n\t}\n};","type ObjectKeys = T extends object\n\t? (keyof T)[]\n\t: T extends number\n\t ? []\n\t : T extends Array | string\n\t ? string[]\n\t : never;\n\nexport function getObjectKeys(obj: T): ObjectKeys {\n\treturn Object.keys(obj) as ObjectKeys;\n}\n","export const IS_DESKTOP = isDesktop();\n\nexport function isDesktop(): boolean {\n\tconst ua = navigator.userAgent;\n\tconst OS = {\n\t\tandroid: false,\n\t\tchromeOS: false,\n\t\tcordova: false,\n\t\tcrosswalk: false,\n\t\tdesktop: false,\n\t\tejecta: false,\n\t\telectron: false,\n\t\tiOS: false,\n\t\tiOSVersion: 0,\n\t\tiPad: false,\n\t\tiPhone: false,\n\t\tkindle: false,\n\t\tlinux: false,\n\t\tmacOS: false,\n\t\tnode: false,\n\t\tnodeWebkit: false,\n\t\tpixelRatio: 1,\n\t\twebApp: false,\n\t\twindows: false,\n\t\twindowsPhone: false,\n\t};\n\n\tif (/Windows/.test(ua)) {\n\t\tOS.windows = true;\n\t} else if (/Mac OS/.test(ua) && !/like Mac OS/.test(ua)) {\n\t\tOS.macOS = true;\n\t} else if (/Android/.test(ua)) {\n\t\tOS.android = true;\n\t} else if (/Linux/.test(ua)) {\n\t\tOS.linux = true;\n\t} else if (/iP[ao]d|iPhone/i.test(ua)) {\n\t\tOS.iOS = true;\n\n\t\tnavigator.appVersion.match(/OS (\\d+)/);\n\n\t\tOS.iOSVersion = parseInt(RegExp.$1, 10);\n\n\t\tOS.iPhone = ua.toLowerCase().indexOf('iphone') !== -1;\n\t\tOS.iPad = ua.toLowerCase().indexOf('ipad') !== -1;\n\t} else if (/Kindle/.test(ua) || /\\bKF[A-Z][A-Z]+/.test(ua) || /Silk.*Mobile Safari/.test(ua)) {\n\t\tOS.kindle = true;\n\n\t\t// This will NOT detect early generations of Kindle Fire, I think there is no reliable way...\n\t\t// E.g. \"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us; Silk/1.1.0-80) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 Silk-Accelerated=true\"\n\t} else if (/CrOS/.test(ua)) {\n\t\tOS.chromeOS = true;\n\t}\n\n\tif (/Windows Phone/i.test(ua) || /IEMobile/i.test(ua)) {\n\t\tOS.android = false;\n\t\tOS.iOS = false;\n\t\tOS.macOS = false;\n\t\tOS.windows = true;\n\t\tOS.windowsPhone = true;\n\t}\n\n\tconst silk = /Silk/.test(ua);\n\n\tif (OS.windows || OS.macOS || (OS.linux && !silk) || OS.chromeOS) {\n\t\tOS.desktop = true;\n\t}\n\n\t// Windows Phone / Table reset\n\tif (OS.windowsPhone || (/Windows NT/i.test(ua) && /Touch/i.test(ua))) {\n\t\tOS.desktop = false;\n\t}\n\n\t// iPad reset\n\tif (OS.macOS && navigator.maxTouchPoints && navigator.maxTouchPoints > 2) {\n\t\tOS.desktop = false;\n\t}\n\n\treturn OS.desktop;\n}\n","// TODO document existing keys\n// Все новые ключи должны быть задокументированы!\nconst DEBUG_STORE_KEYS = {\n\t'profile_clear_pending': false,\n\t'profile-to-import': '',\n\t'disableAllSaves': false,\n\t'disableBeforeUnloadSave': false,\n\t'log_save_requests': false,\n\t'localReplicaDisabled': false,\n\t'chestsExtraLogs': false,\n\t'forceAdError': false,\n\t'forceFakeAds': false,\n\t'forcedLocalSaveError': '',\n\t'adReplacement': '',\n\t'viralMechanicChance': 0,\n\t'event-dates': {},\n\t'skipWinVideo': false,\n\t'skipChestContent': false,\n\t'skipReturnFromAfkScreen': false,\n\t'skipBrokenLevelReset': false,\n\t'pauseBeforePaymentProcess': false,\n\t'pauseBeforePurchaseConsumption': false,\n\t'disableVkEventsLogging': false,\n\t'PlatformPaymentsDisabled': false,\n\t'platformRequestsDelaySeconds': 0,\n\t'clearConsoleOnStart': false,\n\t'accountsState': '',\n\t'throwErrorOnStart': false,\n\t'localStorageType': '',\n\t'serverSaveIntervalMs': 0,\n\t'detailedSaveLogs': false,\n\t'viewerId': '',\n\t'signature': '',\n\t'testPromoGift': null as configs.PromoGift,\n\t'serverRequestsDelaySeconds': 0,\n\t'serverRequestsDelayApis': [] as string[],\n\t'infraErrorsScheduled': false,\n\t'networkErrorsScheduled': false,\n\t'idbErrorsScheduled': 0 as number,\n\t'idbErrorName': '' as string,\n\t'idbErrorMessage': '' as string,\n\t'idbVersion': 1 as number,\n\t'disableMultiTabCheck': false,\n\t'rewardedAdPreloadIntervalMs': 3 * 60 * 1000,\n\t'logProfilesComparison': false,\n\t'localTimeOffsetMinutes': 0 as number,\n\t'serverTimeOffsetMinutes': 0 as number,\n\t'alwaysShowInters': false as boolean,\n\t'forceInterstitials': false as boolean,\n\t'maxDesktopWidth': 0 as number,\n\t'chooseEventRotation': false as boolean,\n\t'chooseEventDifficulty': false as boolean,\n\t'chooseEventRatingPlace': 0 as number,\n\t'storageSuperPrizeType': '' as string,\n\t'useFbFakeBannerAd': false as boolean,\n\t'skipInterstitialOnStart': 0 as number,\n\t'logRandomRewardsWeights': 0 as number,\n\t'disableAllTutors': 0 as number,\n\t'logTimeOnPageVisible': 0 as number,\n\t'conesDropTimerCoef': 1 as number,\n\t'conesDurationMinutes': 0 as number,\n\t'conesMaxRewardsInLine': 0 as number,\n\t'bannersAutoStartDisabled': 0 as number,\n\t'guestId': 0 as number,\n\t'guestCreatedAt': 0 as number,\n\t'skipEventRewardsDisplay': 0 as number,\n\t'xsollaSandboxMode': 0 as number,\n\t'logServerRequestData': 0 as number,\n\t'logServerResponseData': 0 as number,\n\t'loadStartedAt': '',\n\t'loadTimings': '',\n\t'loadPageWasHidden': '',\n\t'assetsLoadDelaySeconds': 0 as number,\n\t'assetsLoadDelayBundles': '',\n\t'assetsLoadErrorsScheduled': 0 as number,\n} as const;\n\nexport type DebugStoreKey = keyof typeof DEBUG_STORE_KEYS;\n\n/**\n * Class representing a debug store for storing and retrieving values from local storage.\n */\nclass DebugStore {\n\t// TODO use types from DEBUG_STORE_KEYS to narrow down return type\n\tpublic get(key: DebugStoreKey, _defaultValue?: string): string | null {\n\t\ttry {\n\t\t\tconst item = localStorage.getItem(key);\n\t\t\tif (item !== null) {\n\t\t\t\treturn item;\n\t\t\t}\n\n\t\t\treturn _defaultValue ?? null;\n\t\t} catch (e) {\n\t\t\treturn _defaultValue ?? null;\n\t\t}\n\t}\n\n\t// TODO use types from DEBUG_STORE_KEYS to narrow down value type\n\tpublic set(key: DebugStoreKey, value: string): boolean {\n\t\ttry {\n\t\t\tlocalStorage.setItem(key, value);\n\t\t\treturn true;\n\t\t} catch (e) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tpublic remove(key: DebugStoreKey): boolean {\n\t\ttry {\n\t\t\tlocalStorage.removeItem(key);\n\t\t\treturn true;\n\t\t} catch (e) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tpublic removeAll(): boolean {\n\t\ttry {\n\t\t\tlocalStorage.clear();\n\t\t\treturn true;\n\t\t} catch (e) {\n\t\t\treturn false;\n\t\t}\n\t}\n}\n\n// TODO make it an EventTarget\nexport const DEBUG_STORE = new DebugStore();\n","import type { FbUrlParams } from 'db://assets/src/platform/api/fb/FBPlatform';\nimport type { OkUrlParams } from 'db://assets/src/platform/api/ok/OkPlatform';\nimport type { VkUrlParams } from 'db://assets/src/platform/api/vk/VkPlatform';\n\nexport type UrlParam =\n\t| 'language'\n\t| 'adminPanel'\n\t| 'throttle'\n\t| 'profile'\n\t| 'clearProfile'\n\t| 'start' // стартовая сцена после загрузки игры\n\t| 'stats'\n\t| 'stateDevTools'\n\t| 'gems'\n\t| 'afkTime' // время между запусками игры (в минутах)\n\t| 'afkScreen' // 0 - afk экран не показывается никогда, 1 - показывается всегда (даже если прошла 0.01 секунда)\n\t| 'skipChest'\n\t| 'mysteryBarrel' // интервал между появлениями mystery barrel (в секундах)\n\t| 'mysteryBarrelType' // например, ad_coins или instant_worker\n\t| 'screen' // какой экран открыть после загрузки уровня\n\t| 'sentry' // sentry=1 включает Сентри для personal env\n\t| 'sentryDebug' // вывод дополнительных логов для Сентри\n\t| 'userId' // фейковый userId для тестирования клиент-серверного взаимодействия\n\t| 'storage' // вид persistent storage, опции - ls (local storage), idb (indexed-db) & server (используется по умолчанию)\n\t| 'storageTimer' // как часто сохраняем профиль в persistent storage (в мс)\n\t| 'viewerId' // id игрока для авторизации\n\t| 'sig' // подпись для авторизации\n\t| 'bannerAd'\n\t| 'bannerAdPosition'\n\t| 'bannerAdSize'\n\t| MainResources\n\t| EventResources\n\t| TutorsParams\n\t| AdsUrlParams\n\t| OkUrlParams\n\t| VkUrlParams\n\t| FbUrlParams;\n\ntype MainResources = 'coins' | 'magicDust' | 'jettons';\n\ntype EventResources = 'eventCoins' | 'eventMagicDust' | 'eventJettons';\n\ntype TutorsParams =\n\t| 'tutors' // tutors=0 to block all tutors\n\t| 'tutorReset' // tutorReset=2a or tutorReset=1,2-a,3 to reset tutor(s) state\n\t| 'tutorComplete' // tutorComplete=2a or tutorComplete=1,2-a,3 to mark tutor(s) as complete\n\t| 'tutorDisable'; // tutorDisable=2a or tutorDisable=1,2-a,3 to disable tutor(s)\n\ntype AdsUrlParams =\n\t| 'noAds' // включает/выключает noAds бонус\n\t| 'fakeAds' // использовать fake ads вместо рекламы от платформы (ok, vk...)\n\t| 'skipInters' // пропускаем показ interstitial ads\n\t| 'skipRewarded' // пропускаем показ rewarded ads\n\t| 'skipAds'; // пропускаем показ любых ads\n\nexport class UrlParams {\n\tprivate static usp: URLSearchParams & { originalSearch?: string };\n\n\tpublic static get(name: UrlParam): string | null {\n\t\tconst search = window.location.search;\n\n\t\tif (!this.usp || this.usp.originalSearch !== search) {\n\t\t\tthis.usp = new URLSearchParams(search);\n\t\t\tthis.usp.originalSearch = search;\n\t\t}\n\n\t\treturn this.usp.get(name);\n\t}\n\n\tpublic static has(name: UrlParam): boolean {\n\t\treturn this.get(name) !== null;\n\t}\n\n\tpublic static getNumber(name: UrlParam, _default = 0): number {\n\t\tconst value = this.get(name);\n\t\tif (value) {\n\t\t\tconst num = parseFloat(value);\n\t\t\treturn isNaN(num) ? _default : num;\n\t\t}\n\n\t\treturn _default;\n\t}\n\n\tpublic static getNumbers(name: UrlParam, _default?: number[]): number[] | null {\n\t\tconst value = this.get(name);\n\t\tif (!value) {\n\t\t\treturn _default ?? null;\n\t\t}\n\n\t\tif (value[0] !== '[' || value[value.length - 1] !== ']') {\n\t\t\tconsole.warn('Malformed url param input', value);\n\t\t\treturn null;\n\t\t}\n\n\t\tconst content = value.slice(1, value.length - 1);\n\t\treturn content.split(',').map((numStr) => {\n\t\t\treturn parseFloat(numStr);\n\t\t});\n\t}\n\n\tpublic static getBool(name: UrlParam, expectedValue = '1'): boolean {\n\t\tconst value = this.get(name);\n\n\t\treturn !!(value && value === expectedValue);\n\t}\n}\n","import { Platform } from '../../BuildConfig';\nimport { UrlParams } from '../UrlParams';\n\nexport function detectPlatform(): Platform {\n\tconst okApiServer = UrlParams.get('api_server');\n\tif (okApiServer && okApiServer.indexOf('ok') !== -1) {\n\t\treturn 'ok';\n\t}\n\n\tconst vkApiUrl = UrlParams.get('api_url');\n\tif (vkApiUrl && (vkApiUrl.includes('vk.com') || vkApiUrl.includes('vk.ru'))) {\n\t\treturn 'vk';\n\t}\n\n\t// это FB билд, запущенный через localhost, используется разработчиками\n\tif (location.host === 'localhost:8080' && UrlParams.has('source')) {\n\t\treturn 'fbInstant';\n\t}\n\n\t// это FB билд на dev/stable/master/prod окружениях\n\tif (location.host.endsWith('apps.fbsbx.com')) {\n\t\treturn 'fbInstant';\n\t}\n\n\tif (location.host.includes('ya-global') || location.hash.includes('yandex') || location.hash.includes('playhop')) {\n\t\treturn 'ya';\n\t}\n\n\t// TODO crazy-games - better way to detect Crazy Games platform\n\tconst source = UrlParams.get('source');\n\tif (source === 'crazy-games') {\n\t\treturn 'cg';\n\t}\n\n\treturn 'none';\n}\n","/**\n * Helper type for any action that can succeed of fail.\n *\n * ```typescript\n * // example with 'match()' from ts-pattern\n * const res = Result.Ok({ test: true });\n * match(res)\n * \t.with({ success: true }, ({ data }) => console.log(data.test))\n * \t.with({ success: false }, ({ error }) => console.log(error))\n * \t.exhaustive();\n * ```\n */\nexport type Result =\n\t| { success: true; data?: TData }\n\t| { success: false; error?: TError };\n\nexport const Result = {\n\tOk: (data?: TData): Result => ({ success: true, data }),\n\tError: (error?: TError): Result => ({ success: false, error }),\n};\n\nexport type AsyncResult = Promise>;\n\nexport const AsyncResult = {\n\tOk: (data?: TData): AsyncResult => Promise.resolve(Result.Ok(data)),\n\tError: (error?: TError): AsyncResult => Promise.resolve(Result.Error(error)),\n\tfromPromise: (promise: Promise) => {\n\t\t// TODO implement\n\t},\n};\n","/**\n * Deferred is a Promise with an exposed resolve() & reject()\n */\nexport interface Deferred {\n\tresolve: (value: T | PromiseLike) => void;\n\treject: (reason: unknown) => void;\n\tpromise: Promise;\n}\n\n// TODO use https://github.com/open-draft/deferred-promise\nexport function deferred(): Deferred {\n\tlet resolve!: (value: T | PromiseLike) => void;\n\tlet reject!: (reason: unknown) => void;\n\tconst promise = new Promise((_resolve, _reject) => {\n\t\tresolve = _resolve;\n\t\treject = _reject;\n\t});\n\treturn { resolve, reject, promise };\n}\n","import { Result } from '../Result';\n\nexport type LoadScriptResult = Result;\n\nexport function loadScript(url: string, async = true) {\n\treturn new Promise((resolve, reject) => {\n\t\tconst script = document.createElement('script');\n\t\tscript.type = 'text/javascript';\n\t\tscript.async = async;\n\t\tscript.src = url;\n\n\t\tscript.addEventListener('load', () => {\n\t\t\tresolve(Result.Ok(script));\n\t\t});\n\n\t\tscript.addEventListener('error', (error) => {\n\t\t\tresolve(Result.Error(error));\n\t\t});\n\n\t\tdocument.body.appendChild(script);\n\t});\n}\n","import { AsyncResult, Result } from '../../assets/src/utils/Result';\nimport { loadScript } from '../../assets/src/utils/net/load-script';\n\nexport interface IPlatformPreloader {\n\t// TODO remove this and use complete deferred instead\n\tinitialized: boolean;\n\n\tloadAndInit(): Promise;\n\n\tsetLoadingProgress(progress: number): void;\n}\n\nexport function stringifyValue(value: unknown): string {\n\tif (typeof value === 'string') {\n\t\treturn value;\n\t}\n\n\ttry {\n\t\treturn JSON.stringify(value);\n\t} catch (e) {\n\t\treturn 'error';\n\t}\n}\n\n// TODO allow to specify fallback url\nexport async function loadScriptWithRetries(url: string, maxAttempts = 3, attempt = 1): AsyncResult {\n\tconsole.log(`platform script load#${attempt} - start (${url})`);\n\n\tconst loadResult = await loadScript(url);\n\tif (loadResult.success === true) {\n\t\tconsole.log(`platform script load#${attempt} - complete`);\n\t\treturn AsyncResult.Ok();\n\t}\n\n\tconsole.warn(`platform script load#${attempt} - failed (${loadResult.error.message})`);\n\n\tconst isLastAttempt = attempt === maxAttempts;\n\tif (isLastAttempt) {\n\t\treturn AsyncResult.Error(loadResult.error.message);\n\t}\n\n\treturn loadScriptWithRetries(url, maxAttempts, attempt + 1);\n}\n","import { Result } from '../../assets/src/utils/Result';\nimport { Deferred, deferred } from '../../assets/src/utils/deferred';\nimport { IPlatformPreloader, loadScriptWithRetries, stringifyValue } from './IPlatformPreloader';\n\nexport class CrazyGamesPlatformPreloader implements IPlatformPreloader {\n\tprivate _initialized = false;\n\tprivate _initCompleted: Deferred;\n\n\tpublic get initialized(): boolean {\n\t\treturn this._initialized;\n\t}\n\n\tpublic set initialized(value: boolean) {\n\t\tthis._initialized = value;\n\t}\n\n\tpublic async loadAndInit(): Promise {\n\t\tif (this._initCompleted) {\n\t\t\treturn this._initCompleted.promise;\n\t\t}\n\n\t\t// проверяем, не была ли загружена sdk ранее самим yandex\n\t\t// if (window['YaGames'] && window['YaGamesAdded']) {\n\t\t// \treturn Result.Ok();\n\t\t// }\n\n\t\tconst sdkLoaded = await loadScriptWithRetries('//sdk.crazygames.com/crazygames-sdk-v3.js');\n\t\tif (sdkLoaded.success === false) {\n\t\t\treturn Result.Error(sdkLoaded.error);\n\t\t}\n\n\t\tif (!('CrazyGames' in window)) {\n\t\t\treturn Result.Error(`script was loaded but CrazyGames SDK is not available`);\n\t\t}\n\n\t\tthis._initCompleted = deferred();\n\n\t\tCrazyGames.SDK.init()\n\t\t\t.then(() => {\n\t\t\t\tCrazyGames.SDK.game.loadingStart();\n\t\t\t\tthis._initialized = true;\n\t\t\t\tthis._initCompleted.resolve(Result.Ok());\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tthis._initCompleted.resolve(Result.Error(stringifyValue(error)));\n\t\t\t});\n\n\t\treturn this._initCompleted.promise;\n\t}\n\n\tpublic setLoadingProgress(progress: number): void {\n\t\t// ничего не делаем, используется в платформах, где есть свой загрузчик\n\t}\n}\n","import { Result } from '../../assets/src/utils/Result';\nimport { Deferred, deferred } from '../../assets/src/utils/deferred';\nimport { IPlatformPreloader, loadScriptWithRetries, stringifyValue } from './IPlatformPreloader';\n\nexport class FbPlatformPreloader implements IPlatformPreloader {\n\tprivate _initialized = false;\n\tprivate _initCompleted: Deferred;\n\n\tpublic get initialized(): boolean {\n\t\treturn this._initialized;\n\t}\n\n\tpublic set initialized(value: boolean) {\n\t\tthis._initialized = value;\n\t}\n\n\tpublic async loadAndInit(): Promise {\n\t\tif (this._initCompleted) {\n\t\t\treturn this._initCompleted.promise;\n\t\t}\n\n\t\t// для personal env (localhost) скрипт с fb sdk подгружаем динамически\n\t\tif (typeof FBInstant === 'undefined') {\n\t\t\tconst fbInstantLoaded = await loadScriptWithRetries('//connect.facebook.net/en_US/fbinstant.7.1.js');\n\t\t\tif (fbInstantLoaded.success === false) {\n\t\t\t\treturn Result.Error(fbInstantLoaded.error);\n\t\t\t}\n\t\t}\n\n\t\t// для остальных окружение sdk уже доступно к этому моменту так как оно подключается через