From 99696f46a46667ffcc30c57923b3a8b1ad17f091 Mon Sep 17 00:00:00 2001 From: Sercan YILDIZ Date: Sat, 3 Oct 2020 18:40:04 +0200 Subject: [PATCH 1/3] Add enableBrowserLogging option --- README.md | 3 ++ dist/beaver-logger.js | 4 +-- dist/beaver-logger.min.js | 2 +- dist/beaver-logger.min.js.map | 2 +- dist/module/logger.js | 6 ++-- src/logger.js | 7 ++-- test/test.js | 68 ++++++++++++++++++++++++++++++++++- 7 files changed, 82 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index a965786..78eaeb6 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,9 @@ var $logger = beaver.Logger({ // Use sendBeacon if supported rather than XHR to send logs; defaults to false enableSendBeacon: true, + + // Enable logs to be displayed in the browser console + enableBrowserLogging: true }); ``` diff --git a/dist/beaver-logger.js b/dist/beaver-logger.js index cba3a79..e08ce51 100644 --- a/dist/beaver-logger.js +++ b/dist/beaver-logger.js @@ -902,7 +902,7 @@ for (var key in source) source.hasOwnProperty(key) && source[key] && !target[key] && (target[key] = source[key]); } function Logger(_ref2) { - var url = _ref2.url, prefix = _ref2.prefix, _ref2$logLevel = _ref2.logLevel, logLevel = void 0 === _ref2$logLevel ? DEFAULT_LOG_LEVEL : _ref2$logLevel, _ref2$transport = _ref2.transport, transport = void 0 === _ref2$transport ? httpTransport : _ref2$transport, _ref2$flushInterval = _ref2.flushInterval, flushInterval = void 0 === _ref2$flushInterval ? 6e4 : _ref2$flushInterval, _ref2$enableSendBeaco = _ref2.enableSendBeacon, enableSendBeacon = void 0 !== _ref2$enableSendBeaco && _ref2$enableSendBeaco; + var url = _ref2.url, prefix = _ref2.prefix, _ref2$logLevel = _ref2.logLevel, logLevel = void 0 === _ref2$logLevel ? DEFAULT_LOG_LEVEL : _ref2$logLevel, _ref2$transport = _ref2.transport, transport = void 0 === _ref2$transport ? httpTransport : _ref2$transport, _ref2$flushInterval = _ref2.flushInterval, flushInterval = void 0 === _ref2$flushInterval ? 6e4 : _ref2$flushInterval, _ref2$enableSendBeaco = _ref2.enableSendBeacon, enableSendBeacon = void 0 !== _ref2$enableSendBeaco && _ref2$enableSendBeaco, _ref2$enableBrowserLo = _ref2.enableBrowserLogging, enableBrowserLogging = void 0 === _ref2$enableBrowserLo || _ref2$enableBrowserLo; var events = []; var tracking = []; var payloadBuilders = []; @@ -910,7 +910,7 @@ var trackingBuilders = []; var headerBuilders = []; function print(level, event, payload) { - if (dom_isBrowser() && window.console && window.console.log && !(LOG_LEVEL_PRIORITY.indexOf(level) > LOG_LEVEL_PRIORITY.indexOf(logLevel))) { + if (dom_isBrowser() && window.console && window.console.log && enableBrowserLogging && !(LOG_LEVEL_PRIORITY.indexOf(level) > LOG_LEVEL_PRIORITY.indexOf(logLevel))) { var args = [ event ]; args.push(payload); (payload.error || payload.warning) && args.push("\n\n", payload.error || payload.warning); diff --git a/dist/beaver-logger.min.js b/dist/beaver-logger.min.js index f03127a..294140c 100644 --- a/dist/beaver-logger.min.js +++ b/dist/beaver-logger.min.js @@ -1,2 +1,2 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("beaver",[],t):"object"==typeof exports?exports.beaver=t():e.beaver=t()}("undefined"!=typeof self?self:this,(function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return{}.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){"use strict";function r(){return(r=Object.assign||function(e){for(var t=1;t>>0)+"__",function(){if("undefined"==typeof WeakMap)return!1;if(void 0===Object.freeze)return!1;try{var e=new WeakMap,t={};return Object.freeze(t),e.set(t,"__testvalue__"),"__testvalue__"===e.get(t)}catch(e){return!1}}())try{this.weakmap=new WeakMap}catch(e){}this.keys=[],this.values=[]}var t=e.prototype;return t._cleanupClosedWindows=function(){for(var e=this.weakmap,t=this.keys,n=0;nF.indexOf(i))){var r=[t];r.push(n),(n.error||n.warning)&&r.push("\n\n",n.error||n.warning);try{window.console[e]&&window.console[e].apply?window.console[e].apply(window.console,r):window.console.log&&window.console.log.apply&&window.console.log.apply(window.console,r)}catch(e){}}}function j(){return l.try((function(){if(L()&&window.location.protocol!==U.FILE&&(h.length||v.length)){for(var e={},n=0;n>>0)+"__",function(){if("undefined"==typeof WeakMap)return!1;if(void 0===Object.freeze)return!1;try{var e=new WeakMap,t={};return Object.freeze(t),e.set(t,"__testvalue__"),"__testvalue__"===e.get(t)}catch(e){return!1}}())try{this.weakmap=new WeakMap}catch(e){}this.keys=[],this.values=[]}var t=e.prototype;return t._cleanupClosedWindows=function(){for(var e=this.weakmap,t=this.keys,n=0;nF.indexOf(i))){var r=[t];r.push(n),(n.error||n.warning)&&r.push("\n\n",n.error||n.warning);try{window.console[e]&&window.console[e].apply?window.console[e].apply(window.console,r):window.console.log&&window.console.log.apply&&window.console.log.apply(window.console,r)}catch(e){}}}function O(){return l.try((function(){if(N()&&window.location.protocol!==U.FILE&&(p.length||w.length)){for(var e={},n=0;n) => void> = [];\n\nexport function dispatchPossiblyUnhandledError(err : mixed, promise : ZalgoPromise) {\n\n if (dispatchedErrors.indexOf(err) !== -1) {\n return;\n }\n\n dispatchedErrors.push(err);\n\n setTimeout(() => {\n if (__DEBUG__) {\n // $FlowFixMe\n throw new Error(`${ err.stack || err.toString() }\\n\\nFrom promise:\\n\\n${ promise.stack }`);\n }\n\n throw err;\n }, 1);\n\n for (let j = 0; j < possiblyUnhandledPromiseHandlers.length; j++) {\n // $FlowFixMe\n possiblyUnhandledPromiseHandlers[j](err, promise);\n }\n}\n\nexport function onPossiblyUnhandledException(handler : (mixed, promise? : ZalgoPromise) => void) : {| cancel : () => void |} {\n possiblyUnhandledPromiseHandlers.push(handler);\n\n return {\n cancel() {\n possiblyUnhandledPromiseHandlers.splice(possiblyUnhandledPromiseHandlers.indexOf(handler), 1);\n }\n };\n}\n","/* @flow */\n\nimport type { ZalgoPromise } from './promise';\n\nlet activeCount = 0;\nlet flushPromise;\n\nfunction flushActive() {\n if (!activeCount && flushPromise) {\n const promise = flushPromise;\n flushPromise = null;\n promise.resolve();\n }\n}\n\nexport function startActive() {\n activeCount += 1;\n}\n\nexport function endActive() {\n activeCount -= 1;\n flushActive();\n}\n\nexport function awaitActive(Zalgo : Class>) : ZalgoPromise { // eslint-disable-line no-undef\n const promise = flushPromise = flushPromise || new Zalgo();\n flushActive();\n return promise;\n}\n","/* @flow */\n\nimport { isPromise } from './utils';\nimport { onPossiblyUnhandledException, dispatchPossiblyUnhandledError } from './exceptions';\nimport { startActive, endActive, awaitActive } from './flush';\n\nexport class ZalgoPromise {\n\n resolved : boolean\n rejected : boolean\n errorHandled : boolean\n value : R\n error : mixed\n // eslint-disable-next-line flowtype/no-mutable-array\n handlers : Array<{|\n promise : ZalgoPromise<*>,\n onSuccess : void | (result : R) => mixed,\n onError : void | (error : mixed) => mixed\n |}>\n dispatching : boolean\n stack : string\n\n constructor(handler : ?(resolve : (result : R) => void, reject : (error : mixed) => void) => void) {\n\n this.resolved = false;\n this.rejected = false;\n this.errorHandled = false;\n\n this.handlers = [];\n\n if (handler) {\n\n let result;\n let error;\n let resolved = false;\n let rejected = false;\n let isAsync = false;\n\n startActive();\n\n try {\n handler(res => {\n if (isAsync) {\n this.resolve(res);\n } else {\n resolved = true;\n result = res;\n }\n\n }, err => {\n if (isAsync) {\n this.reject(err);\n } else {\n rejected = true;\n error = err;\n }\n });\n\n } catch (err) {\n endActive();\n this.reject(err);\n return;\n }\n\n endActive();\n\n isAsync = true;\n\n if (resolved) {\n // $FlowFixMe\n this.resolve(result);\n } else if (rejected) {\n this.reject(error);\n }\n }\n\n if (__DEBUG__) {\n try {\n throw new Error(`ZalgoPromise`);\n } catch (err) {\n this.stack = err.stack;\n }\n }\n }\n\n resolve(result : R) : ZalgoPromise {\n if (this.resolved || this.rejected) {\n return this;\n }\n\n if (isPromise(result)) {\n throw new Error('Can not resolve promise with another promise');\n }\n\n this.resolved = true;\n this.value = result;\n this.dispatch();\n\n return this;\n }\n\n reject(error : mixed) : ZalgoPromise {\n if (this.resolved || this.rejected) {\n return this;\n }\n\n if (isPromise(error)) {\n throw new Error('Can not reject promise with another promise');\n }\n\n if (!error) {\n // $FlowFixMe\n const err = (error && typeof error.toString === 'function' ? error.toString() : Object.prototype.toString.call(error));\n error = new Error(`Expected reject to be called with Error, got ${ err }`);\n }\n\n this.rejected = true;\n this.error = error;\n\n if (!this.errorHandled) {\n setTimeout(() => {\n if (!this.errorHandled) {\n dispatchPossiblyUnhandledError(error, this);\n }\n }, 1);\n }\n\n this.dispatch();\n\n return this;\n }\n\n asyncReject(error : mixed) : ZalgoPromise {\n this.errorHandled = true;\n this.reject(error);\n return this;\n }\n \n dispatch() {\n\n const { dispatching, resolved, rejected, handlers } = this;\n\n if (dispatching) {\n return;\n }\n\n if (!resolved && !rejected) {\n return;\n }\n\n this.dispatching = true;\n startActive();\n\n const chain = (firstPromise : ZalgoPromise, secondPromise : ZalgoPromise) => {\n return firstPromise.then(res => {\n secondPromise.resolve(res);\n }, err => {\n secondPromise.reject(err);\n });\n };\n\n for (let i = 0; i < handlers.length; i++) {\n\n const { onSuccess, onError, promise } = handlers[i];\n\n let result;\n\n if (resolved) {\n\n try {\n result = onSuccess ? onSuccess(this.value) : this.value;\n } catch (err) {\n promise.reject(err);\n continue;\n }\n\n } else if (rejected) {\n\n if (!onError) {\n promise.reject(this.error);\n continue;\n }\n\n try {\n result = onError(this.error);\n } catch (err) {\n promise.reject(err);\n continue;\n }\n }\n\n if (result instanceof ZalgoPromise && (result.resolved || result.rejected)) {\n\n if (result.resolved) {\n promise.resolve(result.value);\n } else {\n promise.reject(result.error);\n }\n\n result.errorHandled = true;\n\n } else if (isPromise(result)) {\n\n if (result instanceof ZalgoPromise && (result.resolved || result.rejected)) {\n if (result.resolved) {\n promise.resolve(result.value);\n } else {\n promise.reject(result.error);\n }\n\n } else {\n // $FlowFixMe\n chain(result, promise);\n }\n\n } else {\n\n promise.resolve(result);\n }\n }\n\n handlers.length = 0;\n this.dispatching = false;\n endActive();\n }\n\n then(onSuccess : void | (result : R) => (ZalgoPromise | Y), onError : void | (error : mixed) => (ZalgoPromise | Y)) : ZalgoPromise {\n\n if (onSuccess && typeof onSuccess !== 'function' && !onSuccess.call) {\n throw new Error('Promise.then expected a function for success handler');\n }\n\n if (onError && typeof onError !== 'function' && !onError.call) {\n throw new Error('Promise.then expected a function for error handler');\n }\n\n const promise : ZalgoPromise = new ZalgoPromise();\n\n this.handlers.push({\n promise,\n onSuccess,\n onError\n });\n\n this.errorHandled = true;\n\n this.dispatch();\n\n return promise;\n }\n\n catch(onError : (error : mixed) => ZalgoPromise | Y) : ZalgoPromise {\n return this.then(undefined, onError);\n }\n\n finally(onFinally : () => mixed) : ZalgoPromise {\n\n if (onFinally && typeof onFinally !== 'function' && !onFinally.call) {\n throw new Error('Promise.finally expected a function');\n }\n\n return this.then((result) => {\n return ZalgoPromise.try(onFinally)\n .then(() => {\n return result;\n });\n }, (err) => {\n return ZalgoPromise.try(onFinally)\n .then(() => {\n throw err;\n });\n });\n }\n\n timeout(time : number, err : ?Error) : ZalgoPromise {\n\n if (this.resolved || this.rejected) {\n return this;\n }\n\n const timeout = setTimeout(() => {\n\n if (this.resolved || this.rejected) {\n return;\n }\n\n this.reject(err || new Error(`Promise timed out after ${ time }ms`));\n\n }, time);\n\n return this.then(result => {\n clearTimeout(timeout);\n return result;\n });\n }\n\n // $FlowFixMe\n toPromise() : Promise {\n // $FlowFixMe\n if (typeof Promise === 'undefined') {\n throw new TypeError(`Could not find Promise`);\n }\n // $FlowFixMe\n return Promise.resolve(this); // eslint-disable-line compat/compat\n }\n\n static resolve(value : X | ZalgoPromise) : ZalgoPromise {\n\n if (value instanceof ZalgoPromise) {\n return value;\n }\n\n if (isPromise(value)) {\n // $FlowFixMe\n return new ZalgoPromise((resolve, reject) => value.then(resolve, reject));\n }\n\n return new ZalgoPromise().resolve(value);\n }\n\n static reject(error : mixed) : ZalgoPromise {\n return new ZalgoPromise().reject(error);\n }\n\n static asyncReject(error : mixed) : ZalgoPromise {\n return new ZalgoPromise().asyncReject(error);\n }\n\n static all>(promises : X) : ZalgoPromise<$TupleMap(ZalgoPromise | Y) => Y>> { // eslint-disable-line no-undef\n\n const promise = new ZalgoPromise();\n let count = promises.length;\n const results = [];\n\n if (!count) {\n promise.resolve(results);\n return promise;\n }\n\n const chain = (i : number, firstPromise : ZalgoPromise, secondPromise : ZalgoPromise) => {\n return firstPromise.then(res => {\n results[i] = res;\n count -= 1;\n if (count === 0) {\n promise.resolve(results);\n }\n }, err => {\n secondPromise.reject(err);\n });\n };\n\n for (let i = 0; i < promises.length; i++) {\n const prom = promises[i];\n\n if (prom instanceof ZalgoPromise) {\n if (prom.resolved) {\n results[i] = prom.value;\n count -= 1;\n continue;\n }\n } else if (!isPromise(prom)) {\n results[i] = prom;\n count -= 1;\n continue;\n }\n\n chain(i, ZalgoPromise.resolve(prom), promise);\n }\n\n if (count === 0) {\n promise.resolve(results);\n }\n\n return promise;\n }\n\n static hash(promises : O) : ZalgoPromise<$ObjMap(ZalgoPromise | Y) => Y>> { // eslint-disable-line no-undef\n const result = {};\n const awaitPromises = [];\n\n for (const key in promises) {\n if (promises.hasOwnProperty(key)) {\n const value = promises[key];\n\n if (isPromise(value)) {\n awaitPromises.push(value.then(res => {\n result[key] = res;\n }));\n } else {\n result[key] = value;\n }\n }\n }\n \n return ZalgoPromise.all(awaitPromises).then(() => result);\n }\n\n static map(items : $ReadOnlyArray, method : (T) => (ZalgoPromise | X)) : ZalgoPromise<$ReadOnlyArray> {\n // $FlowFixMe\n return ZalgoPromise.all(items.map(method));\n }\n\n static onPossiblyUnhandledException(handler : (err : mixed) => void) : {| cancel : () => void |} {\n return onPossiblyUnhandledException(handler);\n }\n\n static try>(method : (...args : A) => (ZalgoPromise | Y), context : ?C, args : ?A) : ZalgoPromise {\n\n if (method && typeof method !== 'function' && !method.call) {\n throw new Error('Promise.try expected a function');\n }\n\n let result;\n\n startActive();\n \n try {\n // $FlowFixMe\n result = method.apply(context, args || []);\n } catch (err) {\n endActive();\n return ZalgoPromise.reject(err);\n }\n\n endActive();\n\n return ZalgoPromise.resolve(result);\n }\n\n static delay(delay : number) : ZalgoPromise {\n return new ZalgoPromise(resolve => {\n setTimeout(resolve, delay);\n });\n }\n\n static isPromise(value : mixed) : boolean {\n\n if (value && value instanceof ZalgoPromise) {\n return true;\n }\n\n return isPromise(value);\n }\n\n static flush() : ZalgoPromise {\n return awaitActive(ZalgoPromise);\n }\n}\n","/* @flow */\n/* eslint max-lines: 0 */\n\nimport { isRegex, noop } from './util';\nimport type { CrossDomainWindowType, SameDomainWindowType, DomainMatcher } from './types';\nimport { PROTOCOL, WILDCARD } from './constants';\n\nconst IE_WIN_ACCESS_ERROR = 'Call was rejected by callee.\\r\\n';\n\nexport function isFileProtocol(win : SameDomainWindowType = window) : boolean {\n return win.location.protocol === PROTOCOL.FILE;\n}\n\nexport function isAboutProtocol(win : SameDomainWindowType = window) : boolean {\n return win.location.protocol === PROTOCOL.ABOUT;\n}\n\nexport function getParent(win? : CrossDomainWindowType = window) : ?CrossDomainWindowType {\n\n if (!win) {\n return;\n }\n\n try {\n if (win.parent && win.parent !== win) {\n return win.parent;\n }\n } catch (err) {\n // pass\n }\n}\n\nexport function getOpener(win? : CrossDomainWindowType = window) : ?CrossDomainWindowType {\n\n if (!win) {\n return;\n }\n\n // Make sure we're not actually an iframe which has had window.open() called on us\n if (getParent(win)) {\n return;\n }\n\n try {\n return win.opener;\n } catch (err) {\n // pass\n }\n}\n\nexport function canReadFromWindow(win : CrossDomainWindowType | SameDomainWindowType) : boolean {\n try {\n // $FlowFixMe\n noop(win && win.location && win.location.href);\n return true;\n } catch (err) {\n // pass\n }\n\n return false;\n}\n\nexport function getActualDomain(win? : SameDomainWindowType = window) : string {\n\n const location = win.location;\n\n if (!location) {\n throw new Error(`Can not read window location`);\n }\n\n const protocol = location.protocol;\n\n if (!protocol) {\n throw new Error(`Can not read window protocol`);\n }\n\n if (protocol === PROTOCOL.FILE) {\n return `${ PROTOCOL.FILE }//`;\n }\n\n if (protocol === PROTOCOL.ABOUT) {\n\n const parent = getParent(win);\n if (parent && canReadFromWindow(parent)) {\n // $FlowFixMe\n return getActualDomain(parent);\n }\n\n return `${ PROTOCOL.ABOUT }//`;\n }\n\n const host = location.host;\n\n if (!host) {\n throw new Error(`Can not read window host`);\n }\n\n return `${ protocol }//${ host }`;\n}\n\nexport function getDomain(win? : SameDomainWindowType = window) : string {\n\n const domain = getActualDomain(win);\n\n if (domain && win.mockDomain && win.mockDomain.indexOf(PROTOCOL.MOCK) === 0) {\n return win.mockDomain;\n }\n\n return domain;\n}\n\nexport function isBlankDomain(win : CrossDomainWindowType) : boolean {\n try {\n // $FlowFixMe\n if (!win.location.href) {\n return true;\n }\n\n if (win.location.href === 'about:blank') {\n return true;\n }\n } catch (err) {\n // pass\n }\n\n return false;\n}\n\nexport function isActuallySameDomain(win : CrossDomainWindowType) : boolean {\n\n try {\n if (win === window) {\n return true;\n }\n\n } catch (err) {\n // pass\n }\n\n try {\n const desc = Object.getOwnPropertyDescriptor(win, 'location');\n\n if (desc && desc.enumerable === false) {\n return false;\n }\n\n } catch (err) {\n // pass\n }\n\n try {\n // $FlowFixMe\n if (isAboutProtocol(win) && canReadFromWindow(win)) {\n return true;\n }\n } catch (err) {\n // pass\n }\n\n try {\n // $FlowFixMe\n if (getActualDomain(win) === getActualDomain(window)) {\n return true;\n }\n\n } catch (err) {\n // pass\n }\n\n return false;\n}\n\nexport function isSameDomain(win : CrossDomainWindowType | SameDomainWindowType) : boolean {\n\n if (!isActuallySameDomain(win)) {\n return false;\n }\n\n try {\n\n if (win === window) {\n return true;\n }\n\n // $FlowFixMe\n if (isAboutProtocol(win) && canReadFromWindow(win)) {\n return true;\n }\n\n // $FlowFixMe\n if (getDomain(window) === getDomain(win)) {\n return true;\n }\n\n } catch (err) {\n // pass\n }\n\n return false;\n}\n\n\nexport function assertSameDomain(win : CrossDomainWindowType | SameDomainWindowType) : SameDomainWindowType {\n if (!isSameDomain(win)) {\n throw new Error(`Expected window to be same domain`);\n }\n\n // $FlowFixMe\n return win;\n}\n\nexport function getParents(win : CrossDomainWindowType) : $ReadOnlyArray {\n\n const result = [];\n\n try {\n\n while (win.parent !== win) {\n result.push(win.parent);\n win = win.parent;\n }\n\n } catch (err) {\n // pass\n }\n\n return result;\n}\n\nexport function isAncestorParent(parent : CrossDomainWindowType, child : CrossDomainWindowType) : boolean {\n\n if (!parent || !child) {\n return false;\n }\n\n const childParent = getParent(child);\n\n if (childParent) {\n return childParent === parent;\n }\n\n if (getParents(child).indexOf(parent) !== -1) {\n return true;\n }\n\n return false;\n}\n\nexport function getFrames(win : CrossDomainWindowType) : $ReadOnlyArray {\n\n const result = [];\n\n let frames;\n\n try {\n frames = win.frames;\n } catch (err) {\n frames = win;\n }\n\n let len;\n\n try {\n len = frames.length;\n } catch (err) {\n // pass\n }\n\n if (len === 0) {\n return result;\n }\n\n if (len) {\n for (let i = 0; i < len; i++) {\n\n let frame;\n\n try {\n frame = frames[i];\n } catch (err) {\n continue;\n }\n\n result.push(frame);\n }\n\n return result;\n }\n\n for (let i = 0; i < 100; i++) {\n let frame;\n\n try {\n frame = frames[i];\n } catch (err) {\n return result;\n }\n\n if (!frame) {\n return result;\n }\n\n result.push(frame);\n }\n\n return result;\n}\n\n\nexport function getAllChildFrames(win : CrossDomainWindowType) : $ReadOnlyArray {\n\n const result = [];\n\n for (const frame of getFrames(win)) {\n result.push(frame);\n\n for (const childFrame of getAllChildFrames(frame)) {\n result.push(childFrame);\n }\n }\n\n return result;\n}\n\nexport function getTop(win? : CrossDomainWindowType = window) : ?CrossDomainWindowType {\n\n try {\n if (win.top) {\n return win.top;\n }\n } catch (err) {\n // pass\n }\n\n if (getParent(win) === win) {\n return win;\n }\n\n try {\n if (isAncestorParent(window, win) && window.top) {\n return window.top;\n }\n } catch (err) {\n // pass\n }\n\n try {\n if (isAncestorParent(win, window) && window.top) {\n return window.top;\n }\n } catch (err) {\n // pass\n }\n\n for (const frame of getAllChildFrames(win)) {\n try {\n if (frame.top) {\n return frame.top;\n }\n } catch (err) {\n // pass\n }\n\n if (getParent(frame) === frame) {\n return frame;\n }\n }\n}\n\nexport function getNextOpener(win? : CrossDomainWindowType = window) : ?CrossDomainWindowType {\n return getOpener(getTop(win) || win);\n}\n\nexport function getUltimateTop(win? : CrossDomainWindowType = window) : CrossDomainWindowType {\n const opener = getNextOpener(win);\n\n if (opener) {\n return getUltimateTop(opener);\n }\n\n return top;\n}\n\nexport function getAllFramesInWindow(win : CrossDomainWindowType) : $ReadOnlyArray {\n const top = getTop(win);\n\n if (!top) {\n throw new Error(`Can not determine top window`);\n }\n\n let result = [ ...getAllChildFrames(top), top ];\n\n // Win may be in shadow dom\n if (result.indexOf(win) === -1) {\n result = [ ...result, win, ...getAllChildFrames(win) ];\n }\n\n return result;\n}\n\nexport function getAllWindows(win? : CrossDomainWindowType = window) : $ReadOnlyArray {\n const frames = getAllFramesInWindow(win);\n const opener = getNextOpener(win);\n\n if (opener) {\n return [ ...getAllWindows(opener), ...frames ];\n } else {\n return frames;\n }\n}\n\nexport function isTop(win : CrossDomainWindowType) : boolean {\n return win === getTop(win);\n}\n\nexport function isFrameWindowClosed(frame : HTMLIFrameElement) : boolean {\n\n if (!frame.contentWindow) {\n return true;\n }\n\n if (!frame.parentNode) {\n return true;\n }\n\n const doc = frame.ownerDocument;\n\n if (doc && doc.documentElement && !doc.documentElement.contains(frame)) {\n let parent = frame;\n\n while (parent.parentNode && parent.parentNode !== parent) {\n parent = parent.parentNode;\n }\n\n // $FlowFixMe\n if (!parent.host || !doc.documentElement.contains(parent.host)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction safeIndexOf(collection : $ReadOnlyArray, item : T) : number {\n for (let i = 0; i < collection.length; i++) {\n\n try {\n if (collection[i] === item) {\n return i;\n }\n } catch (err) {\n // pass\n }\n }\n\n return -1;\n}\n\nconst iframeWindows = [];\nconst iframeFrames = [];\n\nexport function isWindowClosed(win : CrossDomainWindowType, allowMock : boolean = true) : boolean {\n\n try {\n if (win === window) {\n return false;\n }\n } catch (err) {\n return true;\n }\n\n try {\n if (!win) {\n return true;\n }\n\n } catch (err) {\n return true;\n }\n\n try {\n if (win.closed) {\n return true;\n }\n\n } catch (err) {\n\n // I love you so much IE\n\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return false;\n }\n\n return true;\n }\n\n\n if (allowMock && isSameDomain(win)) {\n try {\n // $FlowFixMe\n if (win.mockclosed) {\n return true;\n }\n } catch (err) {\n // pass\n }\n }\n\n // Mobile safari\n\n try {\n if (!win.parent || !win.top) {\n return true;\n }\n } catch (err) {\n // pass\n }\n\n // Yes, this actually happens in IE. win === win errors out when the window\n // is from an iframe, and the iframe was removed from the page.\n\n try {\n noop(win === win); // eslint-disable-line no-self-compare\n } catch (err) {\n return true;\n }\n\n // IE orphaned frame\n\n const iframeIndex = safeIndexOf(iframeWindows, win);\n\n if (iframeIndex !== -1) {\n const frame = iframeFrames[iframeIndex];\n\n if (frame && isFrameWindowClosed(frame)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction cleanIframes() {\n for (let i = 0; i < iframeWindows.length; i++) {\n let closed = false;\n\n try {\n closed = iframeWindows[i].closed;\n } catch (err) {\n // pass\n }\n\n if (closed) {\n iframeFrames.splice(i, 1);\n iframeWindows.splice(i, 1);\n }\n }\n}\n\nexport function linkFrameWindow(frame : HTMLIFrameElement) {\n\n cleanIframes();\n\n if (frame && frame.contentWindow) {\n try {\n iframeWindows.push(frame.contentWindow);\n iframeFrames.push(frame);\n } catch (err) {\n // pass\n }\n }\n}\n\nexport function getUserAgent(win : ?SameDomainWindowType) : string {\n win = win || window;\n return win.navigator.mockUserAgent || win.navigator.userAgent;\n}\n\n\nexport function getFrameByName(win : CrossDomainWindowType, name : string) : ?CrossDomainWindowType {\n\n const winFrames = getFrames(win);\n\n for (const childFrame of winFrames) {\n try {\n // $FlowFixMe\n if (isSameDomain(childFrame) && childFrame.name === name && winFrames.indexOf(childFrame) !== -1) {\n return childFrame;\n }\n } catch (err) {\n // pass\n }\n }\n\n try {\n // $FlowFixMe\n if (winFrames.indexOf(win.frames[name]) !== -1) {\n // $FlowFixMe\n return win.frames[name];\n }\n } catch (err) {\n // pass\n }\n\n try {\n if (winFrames.indexOf(win[name]) !== -1) {\n return win[name];\n }\n } catch (err) {\n // pass\n }\n}\n\nexport function findChildFrameByName(win : CrossDomainWindowType, name : string) : ?CrossDomainWindowType {\n\n const frame = getFrameByName(win, name);\n\n if (frame) {\n return frame;\n }\n\n for (const childFrame of getFrames(win)) {\n const namedFrame = findChildFrameByName(childFrame, name);\n\n if (namedFrame) {\n return namedFrame;\n }\n }\n}\n\nexport function findFrameByName(win : CrossDomainWindowType, name : string) : ?CrossDomainWindowType {\n const frame = getFrameByName(win, name);\n\n if (frame) {\n return frame;\n }\n\n const top = getTop(win) || win;\n\n return findChildFrameByName(top, name);\n}\n\nexport function isParent(win : CrossDomainWindowType, frame : CrossDomainWindowType) : boolean {\n\n const frameParent = getParent(frame);\n\n if (frameParent) {\n return frameParent === win;\n }\n\n for (const childFrame of getFrames(win)) {\n if (childFrame === frame) {\n return true;\n }\n }\n\n return false;\n}\n\nexport function isOpener(parent : CrossDomainWindowType, child : CrossDomainWindowType) : boolean {\n\n return parent === getOpener(child);\n}\n\nexport function getAncestor(win? : CrossDomainWindowType = window) : ?CrossDomainWindowType {\n win = win || window;\n\n const opener = getOpener(win);\n\n if (opener) {\n return opener;\n }\n\n const parent = getParent(win);\n\n if (parent) {\n return parent;\n }\n}\n\nexport function getAncestors(win : CrossDomainWindowType) : $ReadOnlyArray {\n\n const results = [];\n\n let ancestor = win;\n\n while (ancestor) {\n ancestor = getAncestor(ancestor);\n if (ancestor) {\n results.push(ancestor);\n }\n }\n\n return results;\n}\n\n\nexport function isAncestor(parent : CrossDomainWindowType, child : CrossDomainWindowType) : boolean {\n\n const actualParent = getAncestor(child);\n\n if (actualParent) {\n if (actualParent === parent) {\n return true;\n }\n\n return false;\n }\n\n if (child === parent) {\n return false;\n }\n\n if (getTop(child) === child) {\n return false;\n }\n\n for (const frame of getFrames(parent)) {\n if (frame === child) {\n return true;\n }\n }\n\n return false;\n}\n\nexport function isPopup(win? : CrossDomainWindowType = window) : boolean {\n return Boolean(getOpener(win));\n}\n\nexport function isIframe(win? : CrossDomainWindowType = window) : boolean {\n return Boolean(getParent(win));\n}\n\nexport function isFullpage(win? : CrossDomainWindowType = window) : boolean {\n return Boolean(!isIframe(win) && !isPopup(win));\n}\n\nfunction anyMatch(collection1, collection2) : boolean {\n\n for (const item1 of collection1) {\n for (const item2 of collection2) {\n if (item1 === item2) {\n return true;\n }\n }\n }\n\n return false;\n}\n\nexport function getDistanceFromTop(win : CrossDomainWindowType = window) : number {\n let distance = 0;\n let parent = win;\n\n while (parent) {\n parent = getParent(parent);\n if (parent) {\n distance += 1;\n }\n }\n\n return distance;\n}\n\nexport function getNthParent(win : CrossDomainWindowType, n : number = 1) : ?CrossDomainWindowType {\n let parent = win;\n\n for (let i = 0; i < n; i++) {\n if (!parent) {\n return;\n }\n\n parent = getParent(parent);\n }\n\n return parent;\n}\n\nexport function getNthParentFromTop(win : CrossDomainWindowType, n : number = 1) : ?CrossDomainWindowType {\n return getNthParent(win, getDistanceFromTop(win) - n);\n}\n\nexport function isSameTopWindow(win1 : CrossDomainWindowType, win2 : CrossDomainWindowType) : boolean {\n\n const top1 = getTop(win1) || win1;\n const top2 = getTop(win2) || win2;\n\n try {\n if (top1 && top2) {\n if (top1 === top2) {\n return true;\n }\n\n return false;\n }\n } catch (err) {\n // pass\n }\n\n const allFrames1 = getAllFramesInWindow(win1);\n const allFrames2 = getAllFramesInWindow(win2);\n\n if (anyMatch(allFrames1, allFrames2)) {\n return true;\n }\n\n const opener1 = getOpener(top1);\n const opener2 = getOpener(top2);\n\n if (opener1 && anyMatch(getAllFramesInWindow(opener1), allFrames2)) {\n return false;\n }\n\n if (opener2 && anyMatch(getAllFramesInWindow(opener2), allFrames1)) {\n return false;\n }\n\n return false;\n}\n\nexport function matchDomain(pattern : DomainMatcher, origin : DomainMatcher) : boolean {\n\n if (typeof pattern === 'string') {\n\n if (typeof origin === 'string') {\n return pattern === WILDCARD || origin === pattern;\n }\n\n if (isRegex(origin)) {\n return false;\n }\n\n if (Array.isArray(origin)) {\n return false;\n }\n }\n\n if (isRegex(pattern)) {\n\n if (isRegex(origin)) {\n return pattern.toString() === origin.toString();\n }\n\n if (Array.isArray(origin)) {\n return false;\n }\n\n // $FlowFixMe\n return Boolean(origin.match(pattern));\n }\n\n if (Array.isArray(pattern)) {\n\n if (Array.isArray(origin)) {\n return JSON.stringify(pattern) === JSON.stringify(origin);\n }\n\n if (isRegex(origin)) {\n return false;\n }\n\n return pattern.some(subpattern => matchDomain(subpattern, origin));\n }\n\n return false;\n}\n\nexport function stringifyDomainPattern(pattern : DomainMatcher) : string {\n if (Array.isArray(pattern)) {\n return `(${ pattern.join(' | ') })`;\n } else if (isRegex(pattern)) {\n return `RegExp(${ pattern.toString() }`;\n } else {\n return pattern.toString();\n }\n}\n\nexport function getDomainFromUrl(url : string) : string {\n\n let domain;\n\n if (url.match(/^(https?|mock|file):\\/\\//)) {\n domain = url;\n } else {\n return getDomain();\n }\n\n domain = domain.split('/').slice(0, 3).join('/');\n\n return domain;\n}\n\nexport function onCloseWindow(win : CrossDomainWindowType, callback : Function, delay : number = 1000, maxtime : number = Infinity) : {| cancel : () => void |} {\n\n let timeout;\n\n const check = () => {\n\n if (isWindowClosed(win)) {\n\n if (timeout) {\n clearTimeout(timeout);\n }\n\n return callback();\n }\n\n if (maxtime <= 0) {\n clearTimeout(timeout);\n } else {\n maxtime -= delay;\n timeout = setTimeout(check, delay);\n }\n };\n\n check();\n\n return {\n cancel() {\n if (timeout) {\n clearTimeout(timeout);\n }\n }\n };\n}\n\n// eslint-disable-next-line complexity\nexport function isWindow(obj : Object) : boolean {\n\n try {\n if (obj === window) {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (Object.prototype.toString.call(obj) === '[object Window]') {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (window.Window && obj instanceof window.Window) {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (obj && obj.self === obj) {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (obj && obj.parent === obj) {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (obj && obj.top === obj) {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (noop(obj === obj) === '__unlikely_value__') { // eslint-disable-line no-self-compare\n return false;\n }\n\n } catch (err) {\n return true;\n }\n\n try {\n if (obj && obj.__cross_domain_utils_window_check__ === '__unlikely_value__') {\n return false;\n }\n\n } catch (err) {\n return true;\n }\n\n try {\n if ('postMessage' in obj && 'self' in obj && 'location' in obj) {\n return true;\n }\n } catch (err) {\n // pass\n }\n\n return false;\n}\n\nexport function isBrowser() : boolean {\n return (typeof window !== 'undefined' && typeof window.location !== 'undefined');\n}\n\nexport function isCurrentDomain(domain : string) : boolean {\n if (!isBrowser()) {\n return false;\n }\n\n return (getDomain() === domain);\n}\n\nexport function isMockDomain(domain : string) : boolean {\n return domain.indexOf(PROTOCOL.MOCK) === 0;\n}\n\nexport function normalizeMockUrl(url : string) : string {\n if (!isMockDomain(getDomainFromUrl(url))) {\n return url;\n }\n\n if (!__TEST__) {\n throw new Error(`Mock urls not supported out of test mode`);\n }\n\n return url.replace(/^mock:\\/\\/[^/]+/, getActualDomain(window));\n}\n\nexport function closeWindow(win : CrossDomainWindowType) {\n try {\n win.close();\n } catch (err) {\n // pass\n }\n}\n\nexport function getFrameForWindow(win : CrossDomainWindowType) : ?HTMLElement {\n if (isSameDomain(win)) {\n return assertSameDomain(win).frameElement;\n }\n\n for (const frame of document.querySelectorAll('iframe')) {\n if (frame && frame.contentWindow && frame.contentWindow === win) {\n return frame;\n }\n }\n}\n","/* @flow */\n\nexport const PROTOCOL = {\n MOCK: ('mock:' : 'mock:'),\n FILE: ('file:' : 'file:'),\n ABOUT: ('about:' : 'about:')\n};\n\nexport const WILDCARD = '*';\n\nexport const WINDOW_TYPE = {\n IFRAME: ('iframe' : 'iframe'),\n POPUP: ('popup' : 'popup')\n};\n","/* @flow */\n\nexport function safeIndexOf(collection : Array, item : T) : number {\n for (let i = 0; i < collection.length; i++) {\n\n try {\n if (collection[i] === item) {\n return i;\n }\n } catch (err) {\n // pass\n }\n }\n\n return -1;\n}\n\n// eslint-disable-next-line no-unused-vars\nexport function noop(...args : Array) {\n // pass\n}\n","/* @flow */\n\nimport { isWindow, isWindowClosed } from 'cross-domain-utils/src';\n\nimport { hasNativeWeakMap } from './native';\nimport { noop, safeIndexOf } from './util';\n\nexport class CrossDomainSafeWeakMap {\n\n name : string\n weakmap : ?WeakMap\n keys : Array\n values : Array\n\n constructor() {\n // eslint-disable-next-line no-bitwise\n this.name = `__weakmap_${ Math.random() * 1e9 >>> 0 }__`;\n\n if (hasNativeWeakMap()) {\n try {\n this.weakmap = new WeakMap();\n } catch (err) {\n // pass\n }\n }\n\n this.keys = [];\n this.values = [];\n }\n\n _cleanupClosedWindows() {\n\n let weakmap = this.weakmap;\n let keys = this.keys;\n\n for (let i = 0; i < keys.length; i++) {\n let value = keys[i];\n\n if (isWindow(value) && isWindowClosed(value)) {\n\n if (weakmap) {\n try {\n weakmap.delete(value);\n } catch (err) {\n // pass\n }\n }\n\n keys.splice(i, 1);\n this.values.splice(i, 1);\n\n i -= 1;\n }\n }\n }\n\n isSafeToReadWrite(key : K) : boolean {\n\n if (isWindow(key)) {\n return false;\n }\n\n try {\n noop(key && key.self);\n noop(key && key[this.name]);\n } catch (err) {\n return false;\n }\n\n return true;\n }\n\n set(key : K, value : V) {\n\n if (!key) {\n throw new Error(`WeakMap expected key`);\n }\n\n let weakmap = this.weakmap;\n\n if (weakmap) {\n try {\n weakmap.set(key, value);\n } catch (err) {\n delete this.weakmap;\n }\n }\n\n if (this.isSafeToReadWrite(key)) {\n try {\n let name = this.name;\n let entry = key[name];\n\n if (entry && entry[0] === key) {\n entry[1] = value;\n } else {\n Object.defineProperty(key, name, {\n value: [ key, value ],\n writable: true\n });\n }\n\n return;\n\n } catch (err) {\n // pass\n }\n }\n\n this._cleanupClosedWindows();\n\n let keys = this.keys;\n let values = this.values;\n let index = safeIndexOf(keys, key);\n\n if (index === -1) {\n keys.push(key);\n values.push(value);\n } else {\n values[index] = value;\n }\n }\n\n get(key : K) : V | void {\n\n if (!key) {\n throw new Error(`WeakMap expected key`);\n }\n\n let weakmap = this.weakmap;\n\n if (weakmap) {\n try {\n if (weakmap.has(key)) {\n return weakmap.get(key);\n }\n \n } catch (err) {\n delete this.weakmap;\n }\n }\n\n if (this.isSafeToReadWrite(key)) {\n try {\n let entry = key[this.name];\n\n if (entry && entry[0] === key) {\n return entry[1];\n }\n\n return;\n } catch (err) {\n // pass\n }\n }\n\n this._cleanupClosedWindows();\n\n let keys = this.keys;\n let index = safeIndexOf(keys, key);\n\n if (index === -1) {\n return;\n }\n\n return this.values[index];\n }\n\n delete(key : K) {\n\n if (!key) {\n throw new Error(`WeakMap expected key`);\n }\n\n let weakmap = this.weakmap;\n\n if (weakmap) {\n try {\n weakmap.delete(key);\n } catch (err) {\n delete this.weakmap;\n }\n }\n\n if (this.isSafeToReadWrite(key)) {\n try {\n let entry = key[this.name];\n\n if (entry && entry[0] === key) {\n entry[0] = entry[1] = undefined;\n }\n } catch (err) {\n // pass\n }\n }\n\n this._cleanupClosedWindows();\n\n let keys = this.keys;\n let index = safeIndexOf(keys, key);\n\n if (index !== -1) {\n keys.splice(index, 1);\n this.values.splice(index, 1);\n }\n }\n\n has(key : K) : boolean {\n\n if (!key) {\n throw new Error(`WeakMap expected key`);\n }\n\n let weakmap = this.weakmap;\n\n if (weakmap) {\n try {\n if (weakmap.has(key)) {\n return true;\n }\n } catch (err) {\n delete this.weakmap;\n }\n }\n\n if (this.isSafeToReadWrite(key)) {\n try {\n let entry = key[this.name];\n\n if (entry && entry[0] === key) {\n return true;\n }\n\n return false;\n } catch (err) {\n // pass\n }\n }\n\n this._cleanupClosedWindows();\n\n let index = safeIndexOf(this.keys, key);\n return index !== -1;\n }\n\n getOrSet(key : K, getter : () => V) : V {\n if (this.has(key)) {\n // $FlowFixMe\n return this.get(key);\n }\n\n let value = getter();\n this.set(key, value);\n return value;\n }\n}\n","\n/* @flow */\n/* eslint max-lines: 0 */\n\nimport { ZalgoPromise } from 'zalgo-promise/src';\nimport { WeakMap } from 'cross-domain-safe-weakmap/src';\n\nimport type { CancelableType } from './types';\n\nexport function getFunctionName (fn : T) : string {\n return fn.name || fn.__name__ || fn.displayName || 'anonymous';\n}\n\nexport function setFunctionName (fn : T, name : string) : T {\n try {\n delete fn.name;\n fn.name = name;\n } catch (err) {\n // pass\n }\n\n fn.__name__ = fn.displayName = name;\n return fn;\n}\n\nexport function base64encode(str : string) : string {\n if (typeof btoa === 'function') {\n return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (m, p1) => {\n return String.fromCharCode(parseInt(p1, 16));\n }));\n }\n\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(str, 'utf8').toString('base64');\n }\n\n throw new Error(`Can not find window.btoa or Buffer`);\n}\n\nexport function base64decode(str : string) : string {\n if (typeof atob === 'function') {\n return decodeURIComponent(Array.prototype.map.call(atob(str), c => {\n // eslint-disable-next-line prefer-template\n return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);\n }).join(''));\n }\n\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(str, 'base64').toString('utf8');\n }\n\n throw new Error(`Can not find window.atob or Buffer`);\n}\n\nexport function uniqueID() : string {\n\n const chars = '0123456789abcdef';\n\n const randomID = 'xxxxxxxxxx'.replace(/./g, () => {\n return chars.charAt(Math.floor(Math.random() * chars.length));\n });\n\n const timeID = base64encode(\n new Date().toISOString().slice(11, 19).replace('T', '.')\n ).replace(/[^a-zA-Z0-9]/g, '').toLowerCase();\n\n return `${ randomID }_${ timeID }`;\n}\n\nexport function getGlobal() : Object {\n if (typeof window !== 'undefined') {\n return window;\n }\n if (typeof global !== 'undefined') {\n return global;\n }\n if (typeof __GLOBAL__ !== 'undefined') {\n return __GLOBAL__;\n }\n throw new Error(`No global found`);\n}\n\nlet objectIDs;\n\nexport function getObjectID(obj : Object) : string {\n\n objectIDs = objectIDs || new WeakMap();\n\n if (obj === null || obj === undefined || (typeof obj !== 'object' && typeof obj !== 'function')) {\n throw new Error(`Invalid object`);\n }\n\n let uid = objectIDs.get(obj);\n\n if (!uid) {\n uid = `${ typeof obj }:${ uniqueID() }`;\n objectIDs.set(obj, uid);\n }\n\n return uid;\n}\n\nfunction serializeArgs(args : $ReadOnlyArray) : string {\n try {\n return JSON.stringify(Array.prototype.slice.call(args), (subkey, val) => {\n if (typeof val === 'function') {\n return `memoize[${ getObjectID(val) }]`;\n }\n return val;\n });\n } catch (err) {\n throw new Error(`Arguments not serializable -- can not be used to memoize`);\n }\n}\ntype MemoizeOptions = {|\n name? : string,\n time? : number,\n thisNamespace? : boolean\n|};\n\nconst getDefaultMemoizeOptions = () : MemoizeOptions => {\n // $FlowFixMe\n return {};\n};\n\nconst memoizedFunctions = [];\n\nexport function memoize(method : F, options? : MemoizeOptions = getDefaultMemoizeOptions()) : F & {| reset : () => void |} {\n const cacheMap = new WeakMap();\n\n const memoizedFunction = function memoizedFunction(...args) : mixed {\n const cache = cacheMap.getOrSet(options.thisNamespace ? this : method, () => ({}));\n\n const key : string = serializeArgs(args);\n\n const cacheTime = options.time;\n if (cache[key] && cacheTime && (Date.now() - cache[key].time) < cacheTime) {\n delete cache[key];\n }\n\n if (cache[key]) {\n return cache[key].value;\n }\n\n const time = Date.now();\n const value = method.apply(this, arguments);\n\n cache[key] = { time, value };\n\n return cache[key].value;\n };\n\n memoizedFunction.reset = () => {\n cacheMap.delete(options.thisNamespace ? this : method);\n };\n\n memoizedFunctions.push(memoizedFunction);\n\n // $FlowFixMe\n const result : F = memoizedFunction;\n\n return setFunctionName(result, `${ options.name || getFunctionName(method) }::memoized`);\n}\n\nmemoize.clear = () => {\n for (const memoizedFunction of memoizedFunctions) {\n memoizedFunction.reset();\n }\n};\n\nexport function promiseIdentity(item : ZalgoPromise | T) : ZalgoPromise {\n // $FlowFixMe\n return ZalgoPromise.resolve(item);\n}\n\n// eslint-disable-next-line flowtype/no-weak-types\nexport function memoizePromise(method : (...args : $ReadOnlyArray) => ZalgoPromise) : ((...args : $ReadOnlyArray) => ZalgoPromise) {\n let cache = {};\n\n // eslint-disable-next-line flowtype/no-weak-types\n function memoizedPromiseFunction(...args : $ReadOnlyArray) : ZalgoPromise {\n const key : string = serializeArgs(args);\n\n if (cache.hasOwnProperty(key)) {\n return cache[key];\n }\n\n cache[key] = ZalgoPromise.try(() => method.apply(this, arguments))\n .finally(() => {\n delete cache[key];\n });\n\n return cache[key];\n }\n\n memoizedPromiseFunction.reset = () => {\n cache = {};\n };\n\n return setFunctionName(memoizedPromiseFunction, `${ getFunctionName(method) }::promiseMemoized`);\n}\n\ntype PromisifyOptions = {|\n name ? : string\n|};\n\nconst getDefaultPromisifyOptions = () : PromisifyOptions => {\n // $FlowFixMe\n return {};\n};\n\n// eslint-disable-next-line flowtype/no-weak-types\nexport function promisify(method : (...args : $ReadOnlyArray) => R, options : PromisifyOptions = getDefaultPromisifyOptions()) : ((...args : $ReadOnlyArray) => ZalgoPromise) {\n function promisifiedFunction() : ZalgoPromise {\n return ZalgoPromise.try(method, this, arguments);\n }\n\n if (options.name) {\n promisifiedFunction.displayName = `${ options.name }:promisified`;\n }\n\n return setFunctionName(promisifiedFunction, `${ getFunctionName(method) }::promisified`);\n}\n\n// eslint-disable-next-line flowtype/no-weak-types\nexport function inlineMemoize(method : (...args : $ReadOnlyArray) => R, logic : (...args : $ReadOnlyArray) => R, args : $ReadOnlyArray = []) : R {\n // $FlowFixMe\n const cache : {| [string] : R |} = method.__inline_memoize_cache__ = method.__inline_memoize_cache__ || {};\n const key = serializeArgs(args);\n\n if (cache.hasOwnProperty(key)) {\n return cache[key];\n }\n \n const result = cache[key] = logic(...args);\n\n return result;\n}\n\n// eslint-disable-next-line no-unused-vars\nexport function noop(...args : $ReadOnlyArray) {\n // pass\n}\n\nexport function once(method : Function) : Function {\n let called = false;\n\n const onceFunction = function() : mixed {\n if (!called) {\n called = true;\n return method.apply(this, arguments);\n }\n };\n\n return setFunctionName(onceFunction, `${ getFunctionName(method) }::once`);\n}\n\nexport function hashStr(str : string) : number {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n hash += str[i].charCodeAt(0) * Math.pow((i % 10) + 1, 5);\n }\n return Math.floor(Math.pow(Math.sqrt(hash), 5));\n}\n\nexport function strHashStr(str : string) : string {\n let hash = '';\n\n for (let i = 0; i < str.length; i++) {\n let total = (str[i].charCodeAt(0) * i);\n\n if (str[i + 1]) {\n total += (str[i + 1].charCodeAt(0) * (i - 1));\n }\n\n hash += String.fromCharCode(97 + (Math.abs(total) % 26));\n }\n\n return hash;\n}\n\nexport function match(str : string, pattern : RegExp) : ?string {\n const regmatch = str.match(pattern);\n if (regmatch) {\n return regmatch[1];\n }\n}\n\nexport function awaitKey(obj : Object, key : string) : ZalgoPromise {\n return new ZalgoPromise(resolve => {\n\n let value = obj[key];\n\n if (value) {\n return resolve(value);\n }\n\n delete obj[key];\n\n Object.defineProperty(obj, key, {\n\n configurable: true,\n\n set(item) {\n value = item;\n\n if (value) {\n resolve(value);\n }\n },\n\n get() : T {\n return value;\n }\n });\n });\n}\n\nexport function stringifyError(err : mixed, level : number = 1) : string {\n\n if (level >= 3) {\n return 'stringifyError stack overflow';\n }\n\n try {\n if (!err) {\n return ``;\n }\n\n if (typeof err === 'string') {\n return err;\n }\n\n if (err instanceof Error) {\n const stack = err && err.stack;\n const message = err && err.message;\n\n if (stack && message) {\n if (stack.indexOf(message) !== -1) {\n return stack;\n } else {\n return `${ message }\\n${ stack }`;\n }\n } else if (stack) {\n return stack;\n } else if (message) {\n return message;\n }\n }\n\n if (err && err.toString && typeof err.toString === 'function') {\n // $FlowFixMe\n return err.toString();\n }\n\n return Object.prototype.toString.call(err);\n\n } catch (newErr) {\n return `Error while stringifying error: ${ stringifyError(newErr, level + 1) }`;\n }\n}\n\nexport function stringifyErrorMessage(err : mixed) : string {\n\n const defaultMessage = ``;\n\n if (!err) {\n return defaultMessage;\n }\n\n if (err instanceof Error) {\n return err.message || defaultMessage;\n }\n\n if (typeof err.message === 'string') {\n return err.message || defaultMessage;\n }\n\n return defaultMessage;\n}\n\nexport function stringify(item : mixed) : string {\n if (typeof item === 'string') {\n return item;\n }\n\n if (item && item.toString && typeof item.toString === 'function') {\n // $FlowFixMe\n return item.toString();\n }\n\n return Object.prototype.toString.call(item);\n}\n\nexport function domainMatches(hostname : string, domain : string) : boolean {\n hostname = hostname.split('://')[1];\n const index = hostname.indexOf(domain);\n return (index !== -1 && hostname.slice(index) === domain);\n}\n\nexport function patchMethod(obj : Object, name : string, handler : Function) {\n const original = obj[name];\n\n obj[name] = function patchedMethod() : mixed {\n return handler({\n context: this,\n args: Array.prototype.slice.call(arguments),\n original,\n callOriginal: () => original.apply(this, arguments)\n });\n };\n}\n\nexport function extend(obj : T, source : Object) : T {\n if (!source) {\n return obj;\n }\n\n if (Object.assign) {\n return Object.assign(obj, source);\n }\n\n for (const key in source) {\n if (source.hasOwnProperty(key)) {\n obj[key] = source[key];\n }\n }\n\n return obj;\n}\n\n// eslint-disable-next-line no-undef\ntype Values = ({ [string] : T }) => $ReadOnlyArray;\n\nexport const values : Values = (obj) => {\n if (Object.values) {\n // $FlowFixMe\n return Object.values(obj);\n }\n\n const result = [];\n for (const key in obj) {\n if (obj.hasOwnProperty(key)) {\n result.push(obj[key]);\n }\n }\n\n // $FlowFixMe\n return result;\n};\n\nexport const memoizedValues : Values = memoize(values);\n\nexport function perc(pixels : number, percentage : number) : number {\n return Math.round((pixels * percentage) / 100);\n}\n\nexport function min(...args : $ReadOnlyArray) : number {\n return Math.min(...args);\n}\n\nexport function max(...args : $ReadOnlyArray) : number {\n return Math.max(...args);\n}\n\nexport function regexMap(str : string, regexp : RegExp, handler : () => T) : $ReadOnlyArray {\n const results = [];\n\n // $FlowFixMe\n str.replace(regexp, function regexMapMatcher(item) {\n results.push(handler ? handler.apply(null, arguments) : item);\n });\n\n // $FlowFixMe\n return results;\n}\n\nexport function svgToBase64(svg : string) : string {\n return `data:image/svg+xml;base64,${ base64encode(svg) }`;\n}\n\nexport function objFilter(obj : { [string] : T }, filter? : (T, ?string) => mixed = Boolean) : { [string] : R } {\n const result = {};\n\n for (const key in obj) {\n if (!obj.hasOwnProperty(key) || !filter(obj[key], key)) {\n continue;\n }\n\n result[key] = obj[key];\n }\n\n return result;\n}\n\nexport function identity (item : T) : T {\n return item;\n}\n\nexport function regexTokenize(text : string, regexp : RegExp) : $ReadOnlyArray {\n const result = [];\n text.replace(regexp, token => {\n result.push(token);\n return '';\n });\n return result;\n}\n\nexport function promiseDebounce(method : () => ZalgoPromise | T, delay : number = 50) : () => ZalgoPromise {\n\n let promise;\n let timeout;\n\n const promiseDebounced = function() : ZalgoPromise {\n if (timeout) {\n clearTimeout(timeout);\n }\n\n const localPromise = promise = promise || new ZalgoPromise();\n\n timeout = setTimeout(() => {\n promise = null;\n timeout = null;\n\n ZalgoPromise.try(method).then(\n result => { localPromise.resolve(result); },\n err => { localPromise.reject(err); }\n );\n }, delay);\n\n return localPromise;\n };\n\n return setFunctionName(promiseDebounced, `${ getFunctionName(method) }::promiseDebounced`);\n}\n\nexport function safeInterval(method : Function, time : number) : {| cancel : () => void |} {\n\n let timeout;\n\n function loop() {\n timeout = setTimeout(() => {\n method();\n loop();\n }, time);\n }\n\n loop();\n\n return {\n cancel() {\n clearTimeout(timeout);\n }\n };\n}\n\nexport function isInteger(str : string) : boolean {\n return Boolean(str.match(/^[0-9]+$/));\n}\n\nexport function isFloat(str : string) : boolean {\n return Boolean(str.match(/^[0-9]+\\.[0-9]+$/));\n}\n\nexport function serializePrimitive(value : string | number | boolean) : string {\n return value.toString();\n}\n\nexport function deserializePrimitive(value : string) : string | number | boolean {\n if (value === 'true') {\n return true;\n } else if (value === 'false') {\n return false;\n } else if (isInteger(value)) {\n return parseInt(value, 10);\n } else if (isFloat(value)) {\n return parseFloat(value);\n } else {\n return value;\n }\n}\n\nexport function dotify(obj : Object, prefix : string = '', newobj : Object = {}) : { [string] : string } {\n prefix = prefix ? `${ prefix }.` : prefix;\n for (const key in obj) {\n if (!obj.hasOwnProperty(key) || obj[key] === undefined || obj[key] === null || typeof obj[key] === 'function') {\n continue;\n } else if (obj[key] && Array.isArray(obj[key]) && obj[key].length && obj[key].every(val => typeof val !== 'object')) {\n newobj[`${ prefix }${ key }[]`] = obj[key].join(',');\n } else if (obj[key] && typeof obj[key] === 'object') {\n newobj = dotify(obj[key], `${ prefix }${ key }`, newobj);\n } else {\n newobj[`${ prefix }${ key }`] = serializePrimitive(obj[key]);\n }\n }\n return newobj;\n}\n\nexport function undotify(obj : { [string] : string }) : Object {\n \n const result = {};\n\n for (let key in obj) {\n if (!obj.hasOwnProperty(key) || typeof obj[key] !== 'string') {\n continue;\n }\n\n let value = obj[key];\n\n if (key.match(/^.+\\[\\]$/)) {\n key = key.slice(0, -2);\n value = value.split(',').map(deserializePrimitive);\n } else {\n value = deserializePrimitive(value);\n }\n\n let keyResult = result;\n const parts = key.split('.');\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n const isLast = (i + 1 === parts.length);\n const isIndex = !isLast && isInteger(parts[i + 1]);\n\n if (part === 'constructor' || part === 'prototype' || part === '__proto__') {\n throw new Error(`Disallowed key: ${ part }`);\n }\n\n if (isLast) {\n // $FlowFixMe\n keyResult[part] = value;\n } else {\n // $FlowFixMe\n keyResult = keyResult[part] = keyResult[part] || (isIndex ? [] : {});\n }\n }\n }\n\n return result;\n}\n\nexport type EventEmitterType = {|\n on : (eventName : string, handler : Function) => CancelableType,\n once : (eventName : string, handler : Function) => CancelableType,\n trigger : (eventName : string, ...args : $ReadOnlyArray) => ZalgoPromise,\n triggerOnce : (eventName : string, ...args : $ReadOnlyArray) => ZalgoPromise,\n reset : () => void\n|};\n\nexport function eventEmitter() : EventEmitterType {\n const triggered = {};\n let handlers = {};\n\n return {\n\n on(eventName : string, handler : Function) : CancelableType {\n const handlerList = handlers[eventName] = handlers[eventName] || [];\n\n handlerList.push(handler);\n\n let cancelled = false;\n\n return {\n cancel() {\n if (!cancelled) {\n cancelled = true;\n handlerList.splice(handlerList.indexOf(handler), 1);\n }\n\n }\n };\n },\n\n once(eventName : string, handler : Function) : CancelableType {\n\n const listener = this.on(eventName, () => {\n listener.cancel();\n handler();\n });\n\n return listener;\n },\n\n trigger(eventName : string, ...args : $ReadOnlyArray) : ZalgoPromise {\n\n const handlerList = handlers[eventName];\n const promises = [];\n\n if (handlerList) {\n for (const handler of handlerList) {\n promises.push(ZalgoPromise.try(() => handler(...args)));\n }\n }\n\n return ZalgoPromise.all(promises).then(noop);\n },\n\n triggerOnce(eventName : string, ...args : $ReadOnlyArray) : ZalgoPromise {\n\n if (triggered[eventName]) {\n return ZalgoPromise.resolve();\n }\n\n triggered[eventName] = true;\n return this.trigger(eventName, ...args);\n },\n\n reset() {\n handlers = {};\n }\n };\n}\n\nexport function camelToDasherize(string : string) : string {\n return string.replace(/([A-Z])/g, (g) => {\n return `-${ g.toLowerCase() }`;\n });\n}\n\nexport function dasherizeToCamel(string : string) : string {\n return string.replace(/-([a-z])/g, (g) => {\n return g[1].toUpperCase();\n });\n}\n\nexport function capitalizeFirstLetter(string : string) : string {\n return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();\n}\n\nexport function get(item : Object, path : string, def : mixed) : mixed {\n\n if (!path) {\n return def;\n }\n\n const pathParts = path.split('.');\n\n // Loop through each section of our key path\n\n for (let i = 0; i < pathParts.length; i++) {\n\n // If we have an object, we can get the key\n if (typeof item === 'object' && item !== null) {\n item = item[pathParts[i]];\n\n // Otherwise, we should return the default (undefined if not provided)\n } else {\n return def;\n }\n }\n\n // If our final result is undefined, we should return the default\n\n return item === undefined ? def : item;\n}\n\nexport function safeTimeout(method : Function, time : number) {\n\n const interval = safeInterval(() => {\n time -= 100;\n if (time <= 0) {\n interval.cancel();\n method();\n }\n }, 100);\n}\n\nexport function defineLazyProp(obj : Object | $ReadOnlyArray, key : string | number, getter : () => T) {\n if (Array.isArray(obj)) {\n if (typeof key !== 'number') {\n throw new TypeError(`Array key must be number`);\n }\n } else if (typeof obj === 'object' && obj !== null) {\n if (typeof key !== 'string') {\n throw new TypeError(`Object key must be string`);\n }\n }\n \n Object.defineProperty(obj, key, {\n configurable: true,\n enumerable: true,\n get: () => {\n // $FlowFixMe\n delete obj[key];\n const value = getter();\n // $FlowFixMe\n obj[key] = value;\n return value;\n },\n set: (value : T) => {\n // $FlowFixMe\n delete obj[key];\n // $FlowFixMe\n obj[key] = value;\n }\n });\n}\n\nexport function arrayFrom(item : Iterable) : $ReadOnlyArray { // eslint-disable-line no-undef\n return Array.prototype.slice.call(item);\n}\n\nexport function isObject(item : mixed) : boolean {\n return (typeof item === 'object' && item !== null);\n}\n\nexport function isObjectObject(obj : mixed) : boolean {\n return isObject(obj) && Object.prototype.toString.call(obj) === '[object Object]';\n}\n\nexport function isPlainObject(obj : mixed) : boolean {\n if (!isObjectObject(obj)) {\n return false;\n }\n\n // $FlowFixMe\n const constructor = obj.constructor;\n\n if (typeof constructor !== 'function') {\n return false;\n }\n\n const prototype = constructor.prototype;\n\n if (!isObjectObject(prototype)) {\n return false;\n }\n\n if (!prototype.hasOwnProperty('isPrototypeOf')) {\n return false;\n }\n\n return true;\n}\n\nexport function replaceObject | Object> (item : T, replacer : (mixed, string | number, string) => mixed, fullKey : string = '') : T {\n\n if (Array.isArray(item)) {\n const length = item.length;\n const result : Array = [];\n\n for (let i = 0; i < length; i++) {\n\n \n defineLazyProp(result, i, () => {\n const itemKey = fullKey ? `${ fullKey }.${ i }` : `${ i }`;\n const el = item[i];\n\n let child = replacer(el, i, itemKey);\n\n if (isPlainObject(child) || Array.isArray(child)) {\n // $FlowFixMe\n child = replaceObject(child, replacer, itemKey);\n }\n\n return child;\n });\n }\n\n // $FlowFixMe\n return result;\n } else if (isPlainObject(item)) {\n const result = {};\n\n for (const key in item) {\n if (!item.hasOwnProperty(key)) {\n continue;\n }\n\n defineLazyProp(result, key, () => {\n const itemKey = fullKey ? `${ fullKey }.${ key }` : `${ key }`;\n // $FlowFixMe\n const el = item[key];\n\n let child = replacer(el, key, itemKey);\n\n if (isPlainObject(child) || Array.isArray(child)) {\n // $FlowFixMe\n child = replaceObject(child, replacer, itemKey);\n }\n\n return child;\n });\n }\n\n // $FlowFixMe\n return result;\n } else {\n throw new Error(`Pass an object or array`);\n }\n}\n\n\nexport function copyProp(source : Object, target : Object, name : string, def : mixed) {\n if (source.hasOwnProperty(name)) {\n const descriptor = Object.getOwnPropertyDescriptor(source, name);\n // $FlowFixMe\n Object.defineProperty(target, name, descriptor);\n\n } else {\n target[name] = def;\n }\n}\n\ntype RegexResultType = {|\n text : string,\n groups : $ReadOnlyArray,\n start : number,\n end : number,\n length : number,\n replace : (text : string) => string\n|};\n\nexport function regex(pattern : string | RegExp, string : string, start : number = 0) : ?RegexResultType {\n\n if (typeof pattern === 'string') {\n // eslint-disable-next-line security/detect-non-literal-regexp\n pattern = new RegExp(pattern);\n }\n\n const result = string.slice(start).match(pattern);\n\n if (!result) {\n return;\n }\n\n // $FlowFixMe\n const index : number = result.index;\n const regmatch = result[0];\n\n return {\n text: regmatch,\n groups: result.slice(1),\n start: start + index,\n end: start + index + regmatch.length,\n length: regmatch.length,\n\n replace(text : string) : string {\n\n if (!regmatch) {\n return '';\n }\n\n return `${ regmatch.slice(0, start + index) }${ text }${ regmatch.slice(index + regmatch.length) }`;\n }\n };\n}\n\nexport function regexAll(pattern : string | RegExp, string : string) : $ReadOnlyArray {\n\n const matches = [];\n let start = 0;\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const regmatch = regex(pattern, string, start);\n\n if (!regmatch) {\n break;\n }\n\n matches.push(regmatch);\n start = match.end;\n }\n\n return matches;\n}\n\nexport function isDefined(value : ?mixed) : boolean {\n return value !== null && value !== undefined;\n}\n\nexport function cycle(method : Function) : ZalgoPromise {\n return ZalgoPromise.try(method).then(() => cycle(method));\n}\n\nexport function debounce(method : (...args : $ReadOnlyArray) => T, time : number = 100) : (...args : $ReadOnlyArray) => void {\n\n let timeout;\n\n const debounceWrapper = function() {\n clearTimeout(timeout);\n\n timeout = setTimeout(() => {\n return method.apply(this, arguments);\n }, time);\n };\n\n return setFunctionName(debounceWrapper, `${ getFunctionName(method) }::debounced`);\n}\n\nexport function isRegex(item : mixed) : boolean {\n return Object.prototype.toString.call(item) === '[object RegExp]';\n}\n\ntype FunctionProxy = (method : T) => T;\n\n// eslint-disable-next-line flowtype/no-weak-types\nexport const weakMapMemoize : FunctionProxy<*> = (method : (arg : any) => R) : ((...args : $ReadOnlyArray) => R) => {\n\n const weakmap = new WeakMap();\n\n // eslint-disable-next-line flowtype/no-weak-types\n return function weakmapMemoized(arg : any) : R {\n return weakmap.getOrSet(arg, () => method.call(this, arg));\n };\n};\n\ntype FunctionPromiseProxy) => ZalgoPromise> = (T) => T;\n\n// eslint-disable-next-line flowtype/no-weak-types\nexport const weakMapMemoizePromise : FunctionPromiseProxy<*, *> = (method : (arg : any) => ZalgoPromise) : ((...args : $ReadOnlyArray) => ZalgoPromise) => {\n\n const weakmap = new WeakMap();\n\n // eslint-disable-next-line flowtype/no-weak-types\n return function weakmapMemoizedPromise(arg : any) : ZalgoPromise {\n return weakmap.getOrSet(arg, () =>\n method.call(this, arg).finally(() => {\n weakmap.delete(arg);\n }));\n };\n};\n\nexport function getOrSet(obj : O, key : string, getter : () => T) : T {\n if (obj.hasOwnProperty(key)) {\n return obj[key];\n }\n\n const val = getter();\n obj[key] = val;\n return val;\n}\n\nexport type CleanupType = {|\n set : (string, T) => T, // eslint-disable-line no-undef\n register : (Function) => void,\n all : () => ZalgoPromise\n|};\n\nexport function cleanup(obj : Object) : CleanupType {\n\n const tasks = [];\n let cleaned = false;\n\n return {\n set(name : string, item : T) : T {\n if (!cleaned) {\n obj[name] = item;\n this.register(() => {\n delete obj[name];\n });\n }\n return item;\n },\n\n register(method : Function) {\n if (cleaned) {\n method();\n } else {\n tasks.push(once(method));\n }\n },\n\n all() : ZalgoPromise {\n const results = [];\n cleaned = true;\n\n while (tasks.length) {\n const task = tasks.shift();\n results.push(task());\n }\n\n return ZalgoPromise.all(results).then(noop);\n }\n };\n}\n\nexport function tryCatch(fn : () => T) : {| result : T, error : void |} | {| result : void, error : mixed |} {\n let result;\n let error;\n\n try {\n result = fn();\n } catch (err) {\n error = err;\n }\n \n // $FlowFixMe\n return { result, error };\n}\n\n// eslint-disable-next-line flowtype/no-mutable-array\nexport function removeFromArray>(arr : T, item : X) {\n const index = arr.indexOf(item);\n if (index !== -1) {\n arr.splice(index, 1);\n }\n}\n\nexport function assertExists(name : string, thing : void | null | T) : T {\n if (thing === null || typeof thing === 'undefined') {\n throw new Error(`Expected ${ name } to be present`);\n }\n \n return thing;\n}\n\nexport function unique(arr : $ReadOnlyArray) : $ReadOnlyArray {\n const result = {};\n for (const item of arr) {\n result[item] = true;\n }\n return Object.keys(result);\n}\n\nexport const constHas = (constant : T, value : X) : boolean => {\n return memoizedValues(constant).indexOf(value) !== -1;\n};\n\nexport function dedupeErrors(handler : (mixed) => T) : (mixed) => (T | void) {\n const seenErrors = [];\n const seenStringifiedErrors = {};\n\n return (err) => {\n if (seenErrors.indexOf(err) !== -1) {\n return;\n }\n\n seenErrors.push(err);\n\n const stringifiedError = stringifyError(err);\n if (seenStringifiedErrors[stringifiedError]) {\n return;\n }\n\n seenStringifiedErrors[stringifiedError] = true;\n return handler(err);\n };\n}\n\nexport class ExtendableError extends Error {\n constructor(message : string) {\n super(message);\n // eslint-disable-next-line unicorn/custom-error-definition\n this.name = this.constructor.name;\n if (typeof Error.captureStackTrace === 'function') {\n Error.captureStackTrace(this, this.constructor);\n } else {\n this.stack = (new Error(message)).stack;\n }\n }\n}\n \n","/* @flow */\n\nexport function hasNativeWeakMap() : boolean {\n\n if (typeof WeakMap === 'undefined') {\n return false;\n }\n\n if (typeof Object.freeze === 'undefined') {\n return false;\n }\n\n try {\n\n let testWeakMap = new WeakMap();\n let testKey = {};\n let testValue = '__testvalue__';\n\n Object.freeze(testKey);\n\n testWeakMap.set(testKey, testValue);\n\n if (testWeakMap.get(testKey) === testValue) {\n return true;\n }\n\n return false;\n\n } catch (err) {\n\n return false;\n }\n}\n","/* @flow */\n/* eslint max-lines: off */\n\nimport { ZalgoPromise } from 'zalgo-promise/src';\nimport { linkFrameWindow, isWindowClosed,\n type SameDomainWindowType, type CrossDomainWindowType } from 'cross-domain-utils/src';\nimport { WeakMap } from 'cross-domain-safe-weakmap/src';\n\nimport { inlineMemoize, memoize, noop, stringify, capitalizeFirstLetter,\n once, extend, safeInterval, uniqueID, arrayFrom, ExtendableError } from './util';\nimport { isDevice } from './device';\nimport { KEY_CODES, ATTRIBUTES } from './constants';\nimport type { CancelableType } from './types';\n\ntype ElementRefType = string | HTMLElement;\n\nexport function isDocumentReady() : boolean {\n return Boolean(document.body) && (document.readyState === 'complete');\n}\n\nexport function isDocumentInteractive() : boolean {\n return Boolean(document.body) && (document.readyState === 'interactive');\n}\n\nexport function urlEncode(str : string) : string {\n return str.replace(/\\?/g, '%3F').replace(/&/g, '%26').replace(/#/g, '%23').replace(/\\+/g, '%2B');\n}\n\nexport function waitForWindowReady() : ZalgoPromise {\n return inlineMemoize(waitForWindowReady, () : ZalgoPromise => {\n return new ZalgoPromise(resolve => {\n if (isDocumentReady()) {\n resolve();\n }\n\n window.addEventListener('load', () => resolve());\n });\n });\n}\n\ntype WaitForDocumentReady = () => ZalgoPromise;\n\nexport const waitForDocumentReady : WaitForDocumentReady = memoize(() => {\n return new ZalgoPromise(resolve => {\n\n if (isDocumentReady() || isDocumentInteractive()) {\n return resolve();\n }\n\n const interval = setInterval(() => {\n if (isDocumentReady() || isDocumentInteractive()) {\n clearInterval(interval);\n return resolve();\n }\n }, 10);\n });\n});\n\nexport function waitForDocumentBody() : ZalgoPromise {\n return ZalgoPromise.try(() => {\n if (document.body) {\n return document.body;\n }\n\n return waitForDocumentReady().then(() => {\n if (document.body) {\n return document.body;\n }\n\n throw new Error('Document ready but document.body not present');\n });\n });\n}\n\nexport function parseQuery(queryString : string) : Object {\n return inlineMemoize(parseQuery, () : Object => {\n const params = {};\n\n if (!queryString) {\n return params;\n }\n\n if (queryString.indexOf('=') === -1) {\n return params;\n }\n\n for (let pair of queryString.split('&')) {\n pair = pair.split('=');\n\n if (pair[0] && pair[1]) {\n params[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);\n }\n }\n\n return params;\n }, [ queryString ]);\n}\n\n\nexport function getQueryParam(name : string) : string {\n return parseQuery(window.location.search.slice(1))[name];\n}\n\nexport function urlWillRedirectPage(url : string) : boolean {\n\n if (url.indexOf('#') === -1) {\n return true;\n }\n\n if (url.indexOf('#') === 0) {\n return false;\n }\n\n if (url.split('#')[0] === window.location.href.split('#')[0]) {\n return false;\n }\n\n return true;\n}\n\nexport function formatQuery(obj : { [ string ] : string } = {}) : string {\n\n return Object.keys(obj).filter(key => {\n return typeof obj[key] === 'string';\n }).map(key => {\n return `${ urlEncode(key) }=${ urlEncode(obj[key]) }`;\n }).join('&');\n}\n\nexport function extendQuery(originalQuery : string, props : { [ string ] : string } = {}) : string {\n\n if (!props || !Object.keys(props).length) {\n return originalQuery;\n }\n\n return formatQuery({\n ...parseQuery(originalQuery),\n ...props\n });\n}\n\nexport function extendUrl(url : string, options : {| query? : { [string] : string }, hash? : { [string] : string } |}) : string {\n\n const query = options.query || {};\n const hash = options.hash || {};\n\n let originalUrl;\n let originalQuery;\n let originalHash;\n\n [ originalUrl, originalHash ] = url.split('#');\n [ originalUrl, originalQuery ] = originalUrl.split('?');\n\n const queryString = extendQuery(originalQuery, query);\n const hashString = extendQuery(originalHash, hash);\n\n if (queryString) {\n originalUrl = `${ originalUrl }?${ queryString }`;\n }\n\n if (hashString) {\n originalUrl = `${ originalUrl }#${ hashString }`;\n }\n\n return originalUrl;\n}\n\nexport function redirect(url : string, win : CrossDomainWindowType = window) : ZalgoPromise {\n return new ZalgoPromise(resolve => {\n win.location = url;\n if (!urlWillRedirectPage(url)) {\n resolve();\n }\n });\n}\n\nexport function hasMetaViewPort() : boolean {\n const meta = document.querySelector('meta[name=viewport]');\n\n if (isDevice() && window.screen.width < 660 && !meta) {\n return false;\n }\n\n return true;\n}\n\nexport function isElementVisible(el : HTMLElement) : boolean {\n return Boolean(el.offsetWidth || el.offsetHeight || el.getClientRects().length);\n}\n\nexport function getPerformance() : ?Performance {\n return inlineMemoize(getPerformance, () : ?Performance => {\n const performance = window.performance;\n\n if (\n performance &&\n performance.now &&\n performance.timing &&\n performance.timing.connectEnd &&\n performance.timing.navigationStart &&\n (Math.abs(performance.now() - Date.now()) > 1000) &&\n (performance.now() - (performance.timing.connectEnd - performance.timing.navigationStart)) > 0\n ) {\n return performance;\n }\n });\n}\n\nexport function enablePerformance() : boolean {\n return Boolean(getPerformance());\n}\n\nexport function getPageRenderTime() : ZalgoPromise {\n return waitForDocumentReady().then(() => {\n const performance = getPerformance();\n\n if (!performance) {\n return;\n }\n \n const timing = performance.timing;\n\n if (timing.connectEnd && timing.domInteractive) {\n return timing.domInteractive - timing.connectEnd;\n }\n });\n}\n\nexport function htmlEncode(html : string = '') : string {\n return html.toString()\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n .replace(/\\//g, '/');\n}\n\nexport function isBrowser() : boolean {\n return (typeof window !== 'undefined');\n}\n\nexport function querySelectorAll(selector : string, doc : HTMLElement = window.document) : $ReadOnlyArray {\n return Array.prototype.slice.call(doc.querySelectorAll(selector));\n}\n\nexport function onClick(element : HTMLElement, handler : (Event) => void) {\n element.addEventListener('touchstart', noop);\n element.addEventListener('click', handler);\n element.addEventListener('keypress', (event : Event) => {\n // $FlowFixMe\n if (event.keyCode === KEY_CODES.ENTER || event.keyCode === KEY_CODES.SPACE) { // eslint-disable-line unicorn/prefer-event-key\n return handler(event);\n }\n });\n}\n\nexport function getScript({ host = window.location.host, path, reverse = false } : {| host? : string, path : string, reverse? : boolean |}) : ?HTMLScriptElement {\n return inlineMemoize(getScript, () : ?HTMLScriptElement => {\n\n const url = `${ host }${ path }`;\n const scripts = Array.prototype.slice.call(document.getElementsByTagName('script'));\n\n if (reverse) {\n scripts.reverse();\n }\n\n for (const script of scripts) {\n if (!script.src) {\n continue;\n }\n\n const src = script.src.replace(/^https?:\\/\\//, '').split('?')[0];\n\n if (src === url) {\n return script;\n }\n }\n }, [ path ]);\n}\n\nexport function isLocalStorageEnabled() : boolean {\n return inlineMemoize(isLocalStorageEnabled, () => {\n try {\n if (typeof window === 'undefined') {\n return false;\n }\n\n if (window.localStorage) {\n const value = Math.random().toString();\n window.localStorage.setItem('__test__localStorage__', value);\n const result = window.localStorage.getItem('__test__localStorage__');\n window.localStorage.removeItem('__test__localStorage__');\n if (value === result) {\n return true;\n }\n }\n } catch (err) {\n // pass\n }\n return false;\n });\n}\n\nexport function getBrowserLocales() : $ReadOnlyArray<{| country? : string, lang : string |}> {\n const nav = window.navigator; // eslint-disable-line compat/compat\n\n const locales = nav.languages\n ? [ ...nav.languages ]\n : [];\n\n if (nav.language) {\n locales.push(nav.language);\n }\n\n if (nav.userLanguage) {\n locales.push(nav.userLanguage);\n }\n\n return locales.map(locale => {\n\n if (locale && locale.match(/^[a-z]{2}[-_][A-Z]{2}$/)) {\n const [ lang, country ] = locale.split(/[-_]/);\n return { country, lang };\n }\n\n if (locale && locale.match(/^[a-z]{2}$/)) {\n return { lang: locale };\n }\n\n return null;\n\n }).filter(Boolean);\n}\n\n\nexport function appendChild(container : HTMLElement, child : HTMLElement | Text) {\n container.appendChild(child);\n}\n\nexport function isElement(element : mixed) : boolean {\n\n if (element instanceof window.Element) {\n return true;\n }\n\n if (element !== null && typeof element === 'object' && element.nodeType === 1 && typeof element.style === 'object' && typeof element.ownerDocument === 'object') {\n return true;\n }\n\n return false;\n}\n\nexport function getElementSafe(id : ElementRefType, doc : Document | HTMLElement = document) : ?HTMLElement {\n\n if (isElement(id)) {\n // $FlowFixMe\n return id;\n }\n\n if (typeof id === 'string') {\n return doc.querySelector(id);\n }\n}\n\nexport function getElement(id : ElementRefType, doc : Document | HTMLElement = document) : HTMLElement {\n\n const element = getElementSafe(id, doc);\n\n if (element) {\n return element;\n }\n\n throw new Error(`Can not find element: ${ stringify(id) }`);\n}\n\nexport function elementReady(id : ElementRefType) : ZalgoPromise {\n return new ZalgoPromise((resolve, reject) => {\n\n const name = stringify(id);\n let el = getElementSafe(id);\n\n if (el) {\n return resolve(el);\n }\n\n if (isDocumentReady()) {\n return reject(new Error(`Document is ready and element ${ name } does not exist`));\n }\n\n const interval = setInterval(() => {\n\n el = getElementSafe(id);\n\n if (el) {\n clearInterval(interval);\n return resolve(el);\n }\n\n if (isDocumentReady()) {\n clearInterval(interval);\n return reject(new Error(`Document is ready and element ${ name } does not exist`));\n }\n }, 10);\n });\n}\n\n// eslint-disable-next-line unicorn/custom-error-definition\nexport class PopupOpenError extends ExtendableError {}\n\ntype PopupOptions = {|\n name? : string,\n width? : number,\n height? : number,\n top? : number,\n left? : number,\n status? : 0 | 1,\n resizable? : 0 | 1,\n toolbar? : 0 | 1,\n menubar? : 0 | 1,\n scrollbars? : 0 | 1\n|};\n\nexport function popup(url : string, options? : PopupOptions) : CrossDomainWindowType {\n\n // $FlowFixMe\n options = options || {};\n\n const { width, height } = options;\n\n let top = 0;\n let left = 0;\n\n if (width) {\n if (window.outerWidth) {\n left = Math.round((window.outerWidth - width) / 2) + window.screenX;\n } else if (window.screen.width) {\n left = Math.round((window.screen.width - width) / 2);\n }\n }\n\n if (height) {\n if (window.outerHeight) {\n top = Math.round((window.outerHeight - height) / 2) + window.screenY;\n } else if (window.screen.height) {\n top = Math.round((window.screen.height - height) / 2);\n }\n }\n\n if (width && height) {\n // $FlowFixMe\n options = {\n top,\n left,\n width,\n height,\n status: 1,\n toolbar: 0,\n menubar: 0,\n resizable: 1,\n scrollbars: 1,\n ...options\n };\n }\n\n const name = options.name || '';\n delete options.name;\n\n // eslint-disable-next-line array-callback-return\n const params = Object.keys(options).map(key => {\n // $FlowFixMe\n if (options[key] !== null && options[key] !== undefined) {\n return `${ key }=${ stringify(options[key]) }`;\n }\n }).filter(Boolean).join(',');\n\n let win;\n\n try {\n win = window.open(url, name, params, true);\n } catch (err) {\n throw new PopupOpenError(`Can not open popup window - ${ err.stack || err.message }`);\n }\n\n if (isWindowClosed(win)) {\n const err = new PopupOpenError(`Can not open popup window - blocked`);\n throw err;\n }\n\n window.addEventListener('unload', () => win.close());\n\n return win;\n}\n\n\nexport function writeToWindow(win : SameDomainWindowType, html : string) {\n try {\n win.document.open();\n win.document.write(html);\n win.document.close();\n } catch (err) {\n try {\n win.location = `javascript: document.open(); document.write(${ JSON.stringify(html) }); document.close();`;\n } catch (err2) {\n // pass\n }\n }\n}\n\nexport function writeElementToWindow(win : SameDomainWindowType, el : HTMLElement) {\n\n const tag = el.tagName.toLowerCase();\n\n if (tag !== 'html') {\n throw new Error(`Expected element to be html, got ${ tag }`);\n }\n\n const documentElement = win.document.documentElement;\n\n for (const child of arrayFrom(documentElement.children)) {\n documentElement.removeChild(child);\n }\n\n for (const child of arrayFrom(el.children)) {\n documentElement.appendChild(child);\n }\n}\n\nexport function setStyle(el : HTMLElement, styleText : string, doc : Document = window.document) {\n // $FlowFixMe\n if (el.styleSheet) {\n // $FlowFixMe\n el.styleSheet.cssText = styleText;\n } else {\n el.appendChild(doc.createTextNode(styleText));\n }\n}\n\nexport type ElementOptionsType = {|\n style? : { [ string ] : string },\n id? : string,\n class? : ?$ReadOnlyArray,\n attributes? : { [ string ] : string },\n styleSheet? : ?string,\n html? : ?string\n|};\n\nlet awaitFrameLoadPromises : WeakMap>;\n\nexport function awaitFrameLoad(frame : HTMLIFrameElement) : ZalgoPromise {\n awaitFrameLoadPromises = awaitFrameLoadPromises || new WeakMap();\n\n if (awaitFrameLoadPromises.has(frame)) {\n const promise = awaitFrameLoadPromises.get(frame);\n if (promise) {\n return promise;\n }\n }\n\n const promise = new ZalgoPromise((resolve, reject) => {\n frame.addEventListener('load', () => {\n linkFrameWindow(frame);\n resolve(frame);\n });\n\n frame.addEventListener('error', (err : Event) => {\n if (frame.contentWindow) {\n resolve(frame);\n } else {\n reject(err);\n }\n });\n });\n\n awaitFrameLoadPromises.set(frame, promise);\n\n return promise;\n}\n\nexport function awaitFrameWindow(frame : HTMLIFrameElement) : ZalgoPromise {\n return awaitFrameLoad(frame).then(loadedFrame => {\n\n if (!loadedFrame.contentWindow) {\n throw new Error(`Could not find window in iframe`);\n }\n\n return loadedFrame.contentWindow;\n });\n}\n\nconst getDefaultCreateElementOptions = () : ElementOptionsType => {\n // $FlowFixMe\n return {};\n};\n\nexport function createElement(tag : string = 'div', options : ElementOptionsType = getDefaultCreateElementOptions(), container : ?HTMLElement) : HTMLElement {\n\n tag = tag.toLowerCase();\n const element = document.createElement(tag);\n\n if (options.style) {\n extend(element.style, options.style);\n }\n\n if (options.class) {\n element.className = options.class.join(' ');\n }\n\n if (options.id) {\n element.setAttribute('id', options.id);\n }\n\n if (options.attributes) {\n for (const key of Object.keys(options.attributes)) {\n element.setAttribute(key, options.attributes[key]);\n }\n }\n\n if (options.styleSheet) {\n setStyle(element, options.styleSheet);\n }\n\n if (container) {\n appendChild(container, element);\n }\n\n if (options.html) {\n if (tag === 'iframe') {\n // $FlowFixMe\n if (!container || !element.contentWindow) {\n throw new Error(`Iframe html can not be written unless container provided and iframe in DOM`);\n }\n\n // $FlowFixMe\n writeToWindow(element.contentWindow, options.html);\n\n } else {\n element.innerHTML = options.html;\n }\n }\n\n return element;\n}\n\ntype StringMap = {|\n [ string ] : string\n|};\n\nexport type IframeElementOptionsType = {|\n style? : StringMap,\n class? : ?$ReadOnlyArray,\n attributes? : StringMap,\n styleSheet? : ?string,\n html? : ?string,\n url? : ?string\n|};\n\nconst getDefaultIframeOptions = () : IframeElementOptionsType => {\n // $FlowFixMe\n return {};\n};\n\nconst getDefaultStringMap = () : StringMap => {\n // $FlowFixMe\n return {};\n};\n\nexport function iframe(options : IframeElementOptionsType = getDefaultIframeOptions(), container : ?HTMLElement) : HTMLIFrameElement {\n\n const attributes = options.attributes || getDefaultStringMap();\n const style = options.style || getDefaultStringMap();\n\n // $FlowFixMe\n const newAttributes = {\n allowTransparency: 'true',\n ...attributes\n };\n\n // $FlowFixMe\n const newStyle = {\n backgroundColor: 'transparent',\n border: 'none',\n ...style\n };\n\n const frame = createElement('iframe', {\n attributes: newAttributes,\n style: newStyle,\n html: options.html,\n class: options.class\n });\n\n const isIE = window.navigator.userAgent.match(/MSIE|Edge/i); // eslint-disable-line compat/compat\n\n if (!frame.hasAttribute('id')) {\n frame.setAttribute('id', uniqueID());\n }\n\n // $FlowFixMe\n awaitFrameLoad(frame);\n\n if (container) {\n const el = getElement(container);\n el.appendChild(frame);\n }\n\n if (options.url || isIE) {\n frame.setAttribute('src', options.url || 'about:blank');\n }\n\n // $FlowFixMe\n return frame;\n}\n\nexport function addEventListener(obj : HTMLElement, event : string, handler : (event : Event) => void) : CancelableType {\n obj.addEventListener(event, handler);\n return {\n cancel() {\n obj.removeEventListener(event, handler);\n }\n };\n}\n\nexport function bindEvents(element : HTMLElement, eventNames : $ReadOnlyArray, handler : (event : Event) => void) : CancelableType {\n\n handler = once(handler);\n\n for (const eventName of eventNames) {\n element.addEventListener(eventName, handler);\n }\n\n return {\n cancel: once(() => {\n for (const eventName of eventNames) {\n element.removeEventListener(eventName, handler);\n }\n })\n };\n}\n\nconst VENDOR_PREFIXES = [ 'webkit', 'moz', 'ms', 'o' ];\n\nexport function setVendorCSS(element : HTMLElement, name : string, value : string) {\n\n // $FlowFixMe\n element.style[name] = value;\n\n const capitalizedName = capitalizeFirstLetter(name);\n\n for (const prefix of VENDOR_PREFIXES) {\n // $FlowFixMe\n element.style[`${ prefix }${ capitalizedName }`] = value;\n }\n}\n\nconst ANIMATION_START_EVENTS = [ 'animationstart', 'webkitAnimationStart', 'oAnimationStart', 'MSAnimationStart' ];\nconst ANIMATION_END_EVENTS = [ 'animationend', 'webkitAnimationEnd', 'oAnimationEnd', 'MSAnimationEnd' ];\n\nexport function animate(element : ElementRefType, name : string, clean : (Function) => void, timeout : number = 1000) : ZalgoPromise {\n return new ZalgoPromise((resolve, reject) => {\n\n const el = getElement(element);\n\n if (!el) {\n return resolve();\n }\n\n let hasStarted = false;\n\n // eslint-disable-next-line prefer-const\n let startTimeout;\n let endTimeout;\n // eslint-disable-next-line prefer-const\n let startEvent;\n // eslint-disable-next-line prefer-const\n let endEvent;\n\n function cleanUp() {\n clearTimeout(startTimeout);\n clearTimeout(endTimeout);\n startEvent.cancel();\n endEvent.cancel();\n }\n\n startEvent = bindEvents(el, ANIMATION_START_EVENTS, event => {\n\n // $FlowFixMe\n if (event.target !== el || event.animationName !== name) {\n return;\n }\n\n clearTimeout(startTimeout);\n\n event.stopPropagation();\n\n startEvent.cancel();\n hasStarted = true;\n\n endTimeout = setTimeout(() => {\n cleanUp();\n resolve();\n }, timeout);\n });\n\n endEvent = bindEvents(el, ANIMATION_END_EVENTS, event => {\n\n // $FlowFixMe\n if (event.target !== el || event.animationName !== name) {\n return;\n }\n\n cleanUp();\n\n // $FlowFixMe\n if (typeof event.animationName === 'string' && event.animationName !== name) {\n return reject(`Expected animation name to be ${ name }, found ${ event.animationName }`);\n }\n\n return resolve();\n });\n\n setVendorCSS(el, 'animationName', name);\n\n startTimeout = setTimeout(() => {\n if (!hasStarted) {\n cleanUp();\n return resolve();\n }\n }, 200);\n\n if (clean) {\n clean(cleanUp);\n }\n });\n}\n\nexport function makeElementVisible(element : HTMLElement) {\n element.style.setProperty('visibility', '');\n}\n\nexport function makeElementInvisible(element : HTMLElement) {\n element.style.setProperty('visibility', 'hidden', 'important');\n}\n\n\nexport function showElement(element : HTMLElement) {\n element.style.setProperty('display', '');\n}\n\nexport function hideElement(element : HTMLElement) {\n element.style.setProperty('display', 'none', 'important');\n}\n\nexport function destroyElement(element : HTMLElement) {\n if (element && element.parentNode) {\n element.parentNode.removeChild(element);\n }\n}\n\nexport function showAndAnimate(element : HTMLElement, name : string, clean : (Function) => void) : ZalgoPromise {\n const animation = animate(element, name, clean);\n showElement(element);\n return animation;\n}\n\nexport function animateAndHide(element : HTMLElement, name : string, clean : (Function) => void) : ZalgoPromise {\n return animate(element, name, clean).then(() => {\n hideElement(element);\n });\n}\n\nexport function addClass(element : HTMLElement, name : string) {\n element.classList.add(name);\n}\n\nexport function removeClass(element : HTMLElement, name : string) {\n element.classList.remove(name);\n}\n\nexport function isElementClosed(el : HTMLElement) : boolean {\n if (!el || !el.parentNode) {\n return true;\n }\n return false;\n}\n\nexport function watchElementForClose(element : HTMLElement, handler : () => mixed) : CancelableType {\n handler = once(handler);\n\n let interval;\n\n if (isElementClosed(element)) {\n handler();\n } else {\n interval = safeInterval(() => {\n if (isElementClosed(element)) {\n interval.cancel();\n handler();\n }\n }, 50);\n }\n\n return {\n cancel() {\n if (interval) {\n interval.cancel();\n }\n }\n };\n}\n\nexport function fixScripts(el : HTMLElement, doc : Document = window.document) {\n for (const script of querySelectorAll('script', el)) {\n const parentNode = script.parentNode;\n\n if (!parentNode) {\n continue;\n }\n\n const newScript = doc.createElement('script');\n newScript.text = script.textContent;\n parentNode.replaceChild(newScript, script);\n }\n}\n\ntype OnResizeOptions = {|\n width? : boolean,\n height? : boolean,\n interval? : number,\n win? : SameDomainWindowType\n|};\n\nexport function onResize(el : HTMLElement, handler : ({| width : number, height : number |}) => void, { width = true, height = true, interval = 100, win = window } : OnResizeOptions = {}) : {| cancel : () => void |} {\n let currentWidth = el.offsetWidth;\n let currentHeight = el.offsetHeight;\n let canceled = false;\n\n handler({ width: currentWidth, height: currentHeight });\n\n const check = () => {\n if (canceled || !isElementVisible(el)) {\n return;\n }\n\n const newWidth = el.offsetWidth;\n const newHeight = el.offsetHeight;\n\n if ((width && newWidth !== currentWidth) || (height && newHeight !== currentHeight)) {\n handler({ width: newWidth, height: newHeight });\n }\n\n currentWidth = newWidth;\n currentHeight = newHeight;\n };\n\n let observer;\n let timeout;\n\n win.addEventListener('resize', check);\n \n if (typeof win.ResizeObserver !== 'undefined') {\n observer = new win.ResizeObserver(check);\n observer.observe(el);\n timeout = safeInterval(check, interval * 10);\n\n } else if (typeof win.MutationObserver !== 'undefined') {\n observer = new win.MutationObserver(check);\n observer.observe(el, {\n attributes: true,\n childList: true,\n subtree: true,\n characterData: false\n });\n timeout = safeInterval(check, interval * 10);\n } else {\n timeout = safeInterval(check, interval);\n }\n\n return {\n cancel: () => {\n canceled = true;\n observer.disconnect();\n window.removeEventListener('resize', check);\n timeout.cancel();\n }\n };\n}\n\nexport function getResourceLoadTime(url : string) : ?number {\n const performance = getPerformance();\n\n if (!performance) {\n return;\n }\n\n if (typeof performance.getEntries !== 'function') {\n return;\n }\n\n const entries = performance.getEntries();\n\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n\n if (entry && entry.name && entry.name.indexOf(url) === 0 && typeof entry.duration === 'number') {\n return Math.floor(entry.duration);\n }\n }\n}\n\nexport function isShadowElement(element : Node) : boolean {\n while (element.parentNode) {\n element = element.parentNode;\n }\n\n return element.toString() === '[object ShadowRoot]';\n}\n\nexport function getShadowRoot(element : Node) : ?Node {\n while (element.parentNode) {\n element = element.parentNode;\n }\n\n if (isShadowElement(element)) {\n return element;\n }\n}\n\nexport function getShadowHost(element : Node) : ?HTMLElement {\n const shadowRoot = getShadowRoot(element);\n\n // $FlowFixMe\n if (shadowRoot.host) {\n // $FlowFixMe\n return shadowRoot.host;\n }\n}\n\nexport function insertShadowSlot(element : HTMLElement) : HTMLElement {\n const shadowHost = getShadowHost(element);\n\n if (!shadowHost) {\n throw new Error(`Element is not in shadow dom`);\n }\n\n if (isShadowElement(shadowHost)) {\n throw new Error(`Host element is also in shadow dom`);\n }\n\n const slotName = `shadow-slot-${ uniqueID() }`;\n\n const slot = document.createElement('slot');\n slot.setAttribute('name', slotName);\n element.appendChild(slot);\n \n const slotProvider = document.createElement('div');\n slotProvider.setAttribute('slot', slotName);\n shadowHost.appendChild(slotProvider);\n\n return slotProvider;\n}\n\nexport function preventClickFocus(el : HTMLElement) {\n const onFocus = (event : Event) => {\n el.removeEventListener('focus', onFocus);\n event.preventDefault();\n el.blur();\n return false;\n };\n\n el.addEventListener('mousedown', () => {\n el.addEventListener('focus', onFocus);\n setTimeout(() => {\n el.removeEventListener('focus', onFocus);\n }, 1);\n });\n}\n\nexport function getStackTrace() : string {\n try {\n throw new Error('_');\n }\n catch (err) {\n return err.stack || '';\n }\n}\n\nfunction inferCurrentScript() : ?HTMLScriptElement {\n try {\n const stack = getStackTrace();\n const stackDetails = (/.*at [^(]*\\((.*):(.+):(.+)\\)$/ig).exec(stack);\n const scriptLocation = stackDetails && stackDetails[1];\n\n if (!scriptLocation) {\n return;\n }\n\n for (const script of Array.prototype.slice.call(document.getElementsByTagName('script')).reverse()) {\n if (script.src && script.src === scriptLocation) {\n return script;\n }\n }\n\n } catch (err) {\n // pass\n }\n}\n\n// eslint-disable-next-line compat/compat\nlet currentScript = typeof document !== 'undefined' ? document.currentScript : null;\n\ntype GetCurrentScript = () => HTMLScriptElement;\n\nexport const getCurrentScript : GetCurrentScript = memoize(() => {\n if (currentScript) {\n return currentScript;\n }\n\n currentScript = inferCurrentScript();\n\n if (currentScript) {\n return currentScript;\n }\n\n throw new Error('Can not determine current script');\n});\n\nconst currentUID = uniqueID();\n\ntype GetCurrentScriptUID = () => string;\n\nexport const getCurrentScriptUID : GetCurrentScriptUID = memoize(() => {\n let script;\n\n try {\n script = getCurrentScript();\n } catch (err) {\n return currentUID;\n }\n\n let uid = script.getAttribute(ATTRIBUTES.UID);\n\n if (uid && typeof uid === 'string') {\n return uid;\n }\n\n uid = uniqueID();\n script.setAttribute(ATTRIBUTES.UID, uid);\n\n return uid;\n});\n","/* @flow */\n\nexport const KEY_CODES = {\n ENTER: 13,\n SPACE: 32\n};\n\nexport const ATTRIBUTES = {\n UID: 'data-uid'\n};\n","/* @flow */\n\nimport { ZalgoPromise } from 'zalgo-promise/src';\nimport { type SameDomainWindowType } from 'cross-domain-utils/src';\n\ntype RequestOptionsType = {|\n url : string,\n method? : string,\n headers? : { [key : string] : string },\n json? : $ReadOnlyArray | Object,\n data? : { [key : string] : string },\n body? : string,\n win? : SameDomainWindowType,\n timeout? : number\n|};\n\ntype ResponseType = {|\n status : number,\n headers : { [string] : string },\n body : Object\n|};\n\nconst HEADERS = {\n CONTENT_TYPE: 'content-type',\n ACCEPT: 'accept'\n};\n\nconst headerBuilders = [];\n\nfunction parseHeaders(rawHeaders : string = '') : { [string] : string } {\n const result = {};\n for (const line of rawHeaders.trim().split('\\n')) {\n const [ key, ...values ] = line.split(':');\n result[key.toLowerCase()] = values.join(':').trim();\n }\n return result;\n}\n\nexport function request({ url, method = 'get', headers = {}, json, data, body, win = window, timeout = 0 } : RequestOptionsType) : ZalgoPromise {\n return new ZalgoPromise((resolve, reject) => {\n\n if ((json && data) || (json && body) || (data && json)) {\n throw new Error(`Only options.json or options.data or options.body should be passed`);\n }\n\n const normalizedHeaders = {};\n\n for (const key of Object.keys(headers)) {\n normalizedHeaders[key.toLowerCase()] = headers[key];\n }\n\n if (json) {\n normalizedHeaders[HEADERS.CONTENT_TYPE] = normalizedHeaders[HEADERS.CONTENT_TYPE] || 'application/json';\n } else if (data || body) {\n normalizedHeaders[HEADERS.CONTENT_TYPE] = normalizedHeaders[HEADERS.CONTENT_TYPE] || 'application/x-www-form-urlencoded; charset=utf-8';\n }\n\n normalizedHeaders[HEADERS.ACCEPT] = normalizedHeaders[HEADERS.ACCEPT] || 'application/json';\n\n for (const headerBuilder of headerBuilders) {\n const builtHeaders = headerBuilder();\n\n for (const key of Object.keys(builtHeaders)) {\n normalizedHeaders[key.toLowerCase()] = builtHeaders[key];\n }\n }\n\n const xhr = new win.XMLHttpRequest();\n\n xhr.addEventListener('load', function xhrLoad() : void {\n\n const responseHeaders = parseHeaders(this.getAllResponseHeaders());\n\n if (!this.status) {\n return reject(new Error(`Request to ${ method.toLowerCase() } ${ url } failed: no response status code.`));\n }\n \n const contentType = responseHeaders['content-type'];\n const isJSON = contentType && (contentType.indexOf('application/json') === 0 || contentType.indexOf('text/json') === 0);\n let responseBody = this.responseText;\n\n try {\n responseBody = JSON.parse(responseBody);\n } catch (err) {\n if (isJSON) {\n return reject(new Error(`Invalid json: ${ this.responseText }.`));\n }\n }\n\n const res = {\n status: this.status,\n headers: responseHeaders,\n body: responseBody\n };\n\n return resolve(res);\n\n }, false);\n\n xhr.addEventListener('error', (evt) => {\n reject(new Error(`Request to ${ method.toLowerCase() } ${ url } failed: ${ evt.toString() }.`));\n }, false);\n\n xhr.open(method, url, true);\n\n for (const key in normalizedHeaders) {\n if (normalizedHeaders.hasOwnProperty(key)) {\n xhr.setRequestHeader(key, normalizedHeaders[key]);\n }\n }\n\n if (json) {\n body = JSON.stringify(json);\n } else if (data) {\n body = Object.keys(data).map(key => {\n return `${ encodeURIComponent(key) }=${ data ? encodeURIComponent(data[key]) : '' }`;\n }).join('&');\n }\n\n xhr.timeout = timeout;\n xhr.ontimeout = function xhrTimeout() {\n reject(new Error(`Request to ${ method.toLowerCase() } ${ url } has timed out`));\n };\n\n xhr.send(body);\n });\n}\n\nexport function addHeaderBuilder(method : () => { [string] : string }) {\n headerBuilders.push(method);\n}\n","/* @flow */\n\nexport const LOG_LEVEL = {\n DEBUG: ('debug' : 'debug'),\n INFO: ('info' : 'info'),\n WARN: ('warn' : 'warn'),\n ERROR: ('error' : 'error')\n};\n\nexport const PROTOCOL = {\n FILE: 'file:'\n};\n","/* @flow */\n\nimport { LOG_LEVEL } from './constants';\n\nexport const AUTO_FLUSH_LEVEL = [ LOG_LEVEL.WARN, LOG_LEVEL.ERROR ];\n\nexport const LOG_LEVEL_PRIORITY = [ LOG_LEVEL.ERROR, LOG_LEVEL.WARN, LOG_LEVEL.INFO, LOG_LEVEL.DEBUG ];\n\nexport const FLUSH_INTERVAL = 60 * 1000;\n\nexport const DEFAULT_LOG_LEVEL : $Values = __DEBUG__ ? LOG_LEVEL.DEBUG : LOG_LEVEL.WARN;\n","/* @flow */\n\nimport { ZalgoPromise } from 'zalgo-promise/src';\nimport { request, isBrowser, promiseDebounce, noop, safeInterval, objFilter } from 'belter/src';\n\nimport { DEFAULT_LOG_LEVEL, LOG_LEVEL_PRIORITY, AUTO_FLUSH_LEVEL, FLUSH_INTERVAL } from './config';\nimport { LOG_LEVEL, PROTOCOL } from './constants';\n\ntype TransportOptions = {|\n url : string,\n method : string,\n headers : { [string] : string },\n json : Object,\n enableSendBeacon : boolean\n|};\n\ntype Payload = { [string] : string | boolean };\ntype Transport = (TransportOptions) => ZalgoPromise;\n\ntype LoggerOptions = {|\n url : string,\n prefix? : string,\n logLevel? : $Values,\n transport? : Transport,\n flushInterval? : number,\n enableSendBeacon? : boolean\n|};\n\ntype ClientPayload = { [string] : ?string | ?boolean };\ntype Log = (name : string, payload? : ClientPayload) => LoggerType; // eslint-disable-line no-use-before-define\ntype Track = (payload : ClientPayload) => LoggerType; // eslint-disable-line no-use-before-define\n\ntype Builder = (Payload) => ClientPayload;\ntype AddBuilder = (Builder) => LoggerType; // eslint-disable-line no-use-before-define\n\nexport type LoggerType = {|\n debug : Log,\n info : Log,\n warn : Log,\n error : Log,\n\n track : Track,\n\n flush : () => ZalgoPromise,\n immediateFlush : () => ZalgoPromise,\n\n addPayloadBuilder : AddBuilder,\n addMetaBuilder : AddBuilder,\n addTrackingBuilder : AddBuilder,\n addHeaderBuilder : AddBuilder,\n\n setTransport : (Transport) => LoggerType\n|};\n\nfunction httpTransport({ url, method, headers, json, enableSendBeacon = false } : TransportOptions) : ZalgoPromise {\n const hasHeaders = headers && Object.keys(headers).length;\n if (window && window.navigator.sendBeacon && !hasHeaders && enableSendBeacon && window.Blob) {\n return new ZalgoPromise(resolve => {\n const blob = new Blob([ JSON.stringify(json) ], { type: 'application/json' });\n resolve(window.navigator.sendBeacon(url, blob));\n });\n } else {\n return request({ url, method, headers, json }).then(noop);\n }\n}\n\nfunction extendIfDefined(target : { [string] : string | boolean }, source : { [string] : ?string | ?boolean }) {\n for (const key in source) {\n if (source.hasOwnProperty(key) && source[key] && !target[key]) {\n target[key] = source[key];\n }\n }\n}\n\nexport function Logger({ url, prefix, logLevel = DEFAULT_LOG_LEVEL, transport = httpTransport, flushInterval = FLUSH_INTERVAL, enableSendBeacon = false } : LoggerOptions) : LoggerType {\n\n let events : Array<{| level : $Values, event : string, payload : Payload |}> = [];\n let tracking : Array = [];\n\n const payloadBuilders : Array = [];\n const metaBuilders : Array = [];\n const trackingBuilders : Array = [];\n const headerBuilders : Array = [];\n\n function print(level : $Values, event : string, payload : Payload) {\n\n if (!isBrowser() || !window.console || !window.console.log) {\n return;\n }\n\n if (LOG_LEVEL_PRIORITY.indexOf(level) > LOG_LEVEL_PRIORITY.indexOf(logLevel)) {\n return;\n }\n\n const args = [ event ];\n\n args.push(payload);\n\n if (payload.error || payload.warning) {\n args.push('\\n\\n', payload.error || payload.warning);\n }\n\n try {\n if (window.console[level] && window.console[level].apply) {\n window.console[level].apply(window.console, args);\n } else if (window.console.log && window.console.log.apply) {\n window.console.log.apply(window.console, args);\n }\n } catch (err) {\n // pass\n }\n }\n\n function immediateFlush() : ZalgoPromise {\n return ZalgoPromise.try(() => {\n if (!isBrowser() || window.location.protocol === PROTOCOL.FILE) {\n return;\n }\n\n if (!events.length && !tracking.length) {\n return;\n }\n\n const meta = {};\n for (const builder of metaBuilders) {\n extendIfDefined(meta, builder(meta));\n }\n\n const headers = {};\n for (const builder of headerBuilders) {\n extendIfDefined(headers, builder(headers));\n }\n\n const res = transport({\n method: 'POST',\n url,\n headers,\n json: {\n events,\n meta,\n tracking\n },\n enableSendBeacon\n });\n\n events = [];\n tracking = [];\n\n return res.then(noop);\n });\n }\n\n const flush = promiseDebounce(immediateFlush);\n\n function enqueue(level : $Values, event : string, payload : Payload) {\n\n events.push({\n level,\n event,\n payload\n });\n\n if (AUTO_FLUSH_LEVEL.indexOf(level) !== -1) {\n flush();\n }\n }\n\n function log(level : $Values, event : string, payload = {}) : LoggerType {\n\n if (!isBrowser()) {\n return logger; // eslint-disable-line no-use-before-define\n }\n\n if (prefix) {\n event = `${ prefix }_${ event }`;\n }\n\n const logPayload : Payload = {\n ...objFilter(payload),\n timestamp: Date.now().toString()\n };\n\n for (const builder of payloadBuilders) {\n extendIfDefined(logPayload, builder(logPayload));\n }\n\n enqueue(level, event, logPayload);\n print(level, event, logPayload);\n\n return logger; // eslint-disable-line no-use-before-define\n }\n\n function addBuilder(builders, builder) : LoggerType {\n builders.push(builder);\n return logger; // eslint-disable-line no-use-before-define\n }\n\n function addPayloadBuilder(builder) : LoggerType {\n return addBuilder(payloadBuilders, builder);\n }\n\n function addMetaBuilder(builder) : LoggerType {\n return addBuilder(metaBuilders, builder);\n }\n\n function addTrackingBuilder(builder) : LoggerType {\n return addBuilder(trackingBuilders, builder);\n }\n\n function addHeaderBuilder(builder) : LoggerType {\n return addBuilder(headerBuilders, builder);\n }\n\n function debug(event, payload) : LoggerType {\n return log(LOG_LEVEL.DEBUG, event, payload);\n }\n\n function info(event, payload) : LoggerType {\n return log(LOG_LEVEL.INFO, event, payload);\n }\n\n function warn(event, payload) : LoggerType {\n return log(LOG_LEVEL.WARN, event, payload);\n }\n\n function error(event, payload) : LoggerType {\n return log(LOG_LEVEL.ERROR, event, payload);\n }\n\n function track(payload = {}) : LoggerType {\n if (!isBrowser()) {\n return logger; // eslint-disable-line no-use-before-define\n }\n\n const trackingPayload : Payload = objFilter(payload);\n\n for (const builder of trackingBuilders) {\n extendIfDefined(trackingPayload, builder(trackingPayload));\n }\n\n print(LOG_LEVEL.DEBUG, 'track', trackingPayload);\n tracking.push(trackingPayload);\n\n return logger; // eslint-disable-line no-use-before-define\n }\n\n function setTransport(newTransport : Transport) : LoggerType {\n transport = newTransport;\n return logger; // eslint-disable-line no-use-before-define\n }\n\n if (isBrowser()) {\n safeInterval(flush, flushInterval);\n }\n\n if (typeof window === 'object') {\n window.addEventListener('beforeunload', () => {\n immediateFlush();\n });\n\n window.addEventListener('unload', () => {\n immediateFlush();\n });\n }\n\n const logger = {\n debug,\n info,\n warn,\n error,\n track,\n flush,\n immediateFlush,\n addPayloadBuilder,\n addMetaBuilder,\n addTrackingBuilder,\n addHeaderBuilder,\n setTransport\n };\n\n return logger;\n}\n"],"sourceRoot":""} \ No newline at end of file +{"version":3,"sources":["webpack://beaver/webpack/universalModuleDefinition","webpack://beaver/webpack/bootstrap","webpack://beaver/./node_modules/@babel/runtime/helpers/esm/extends.js","webpack://beaver/./node_modules/zalgo-promise/src/utils.js","webpack://beaver/./node_modules/zalgo-promise/src/exceptions.js","webpack://beaver/./node_modules/zalgo-promise/src/flush.js","webpack://beaver/./node_modules/zalgo-promise/src/promise.js","webpack://beaver/./node_modules/cross-domain-utils/src/utils.js","webpack://beaver/./node_modules/cross-domain-utils/src/constants.js","webpack://beaver/./node_modules/cross-domain-safe-weakmap/src/util.js","webpack://beaver/./node_modules/cross-domain-safe-weakmap/src/weakmap.js","webpack://beaver/./node_modules/belter/src/util.js","webpack://beaver/./node_modules/cross-domain-safe-weakmap/src/native.js","webpack://beaver/./node_modules/belter/src/dom.js","webpack://beaver/./node_modules/belter/src/constants.js","webpack://beaver/./node_modules/belter/src/http.js","webpack://beaver/./src/constants.js","webpack://beaver/./src/config.js","webpack://beaver/./src/logger.js"],"names":["root","factory","exports","module","define","amd","self","this","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","hasOwnProperty","p","s","_extends","assign","target","arguments","length","source","apply","isPromise","item","Promise","window","Window","constructor","toString","then","err","flushPromise","dispatchedErrors","possiblyUnhandledPromiseHandlers","activeCount","flushActive","promise","resolve","startActive","endActive","ZalgoPromise","handler","resolved","rejected","errorHandled","error","handlers","dispatching","stack","result","isAsync","res","reject","Error","dispatch","setTimeout","indexOf","push","j","dispatchPossiblyUnhandledError","asyncReject","chain","firstPromise","secondPromise","onSuccess","onError","catch","undefined","finally","onFinally","try","timeout","time","clearTimeout","toPromise","TypeError","all","promises","count","results","prom","hash","awaitPromises","map","items","method","onPossiblyUnhandledException","cancel","splice","context","args","delay","flush","IE_WIN_ACCESS_ERROR","isAboutProtocol","win","location","protocol","canReadFromWindow","getActualDomain","PROTOCOL","parent","getParent","host","getDomain","domain","mockDomain","iframeWindows","iframeFrames","isWindowClosed","allowMock","closed","message","desc","getOwnPropertyDescriptor","isActuallySameDomain","isSameDomain","mockclosed","top","iframeIndex","collection","safeIndexOf","frame","contentWindow","parentNode","doc","ownerDocument","documentElement","contains","isFrameWindowClosed","isWindow","obj","__cross_domain_utils_window_check__","objectIDs","CrossDomainSafeWeakMap","weakmap","keys","values","Math","random","WeakMap","freeze","testWeakMap","testKey","set","hasNativeWeakMap","_cleanupClosedWindows","delete","isSafeToReadWrite","entry","writable","index","has","getOrSet","getFunctionName","fn","__name__","displayName","setFunctionName","uniqueID","chars","replace","charAt","floor","str","btoa","encodeURIComponent","p1","String","fromCharCode","parseInt","Buffer","from","base64encode","Date","toISOString","slice","toLowerCase","serializeArgs","JSON","stringify","Array","subkey","val","uid","getObjectID","memoizedFunctions","memoize","options","cacheMap","memoizedFunction","cache","thisNamespace","cacheTime","now","reset","noop","objFilter","filter","Boolean","isDocumentReady","document","body","readyState","isDocumentInteractive","isBrowser","clear","interval","setInterval","clearInterval","currentScript","getCurrentScript","getStackTrace","stackDetails","exec","scriptLocation","getElementsByTagName","reverse","script","src","inferCurrentScript","currentUID","getAttribute","setAttribute","headerBuilders","LOG_LEVEL","DEBUG","INFO","WARN","ERROR","FILE","AUTO_FLUSH_LEVEL","LOG_LEVEL_PRIORITY","DEFAULT_LOG_LEVEL","httpTransport","url","headers","json","enableSendBeacon","hasHeaders","navigator","sendBeacon","Blob","blob","type","data","normalizedHeaders","builtHeaders","headerBuilder","xhr","XMLHttpRequest","addEventListener","responseHeaders","rawHeaders","trim","split","join","parseHeaders","getAllResponseHeaders","status","contentType","isJSON","responseBody","responseText","parse","evt","open","setRequestHeader","ontimeout","send","request","extendIfDefined","Logger","prefix","logLevel","transport","flushInterval","enableBrowserLogging","events","tracking","payloadBuilders","metaBuilders","trackingBuilders","print","level","event","payload","console","log","warning","immediateFlush","meta","builder","localPromise","logger","logPayload","timestamp","enqueue","addBuilder","builders","loop","safeInterval","debug","info","warn","track","trackingPayload","addPayloadBuilder","addMetaBuilder","addTrackingBuilder","addHeaderBuilder","setTransport","newTransport"],"mappings":"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","file":"beaver-logger.min.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"beaver\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"beaver\"] = factory();\n\telse\n\t\troot[\"beaver\"] = factory();\n})((typeof self !== 'undefined' ? self : this), function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n","export default function _extends() {\n _extends = Object.assign || function (target) {\n for (var i = 1; i < arguments.length; i++) {\n var source = arguments[i];\n\n for (var key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n target[key] = source[key];\n }\n }\n }\n\n return target;\n };\n\n return _extends.apply(this, arguments);\n}","/* @flow */\n\nexport function isPromise(item : mixed) : boolean {\n try {\n if (!item) {\n return false;\n }\n\n if (typeof Promise !== 'undefined' && item instanceof Promise) {\n return true;\n }\n\n if (typeof window !== 'undefined' && typeof window.Window === 'function' && item instanceof window.Window) {\n return false;\n }\n\n if (typeof window !== 'undefined' && typeof window.constructor === 'function' && item instanceof window.constructor) {\n return false;\n }\n\n const toString = ({}).toString;\n\n if (toString) {\n const name = toString.call(item);\n\n if (name === '[object Window]' || name === '[object global]' || name === '[object DOMWindow]') {\n return false;\n }\n }\n\n if (typeof item.then === 'function') {\n return true;\n }\n } catch (err) {\n return false;\n }\n\n return false;\n}\n","/* @flow */\n\nimport type { ZalgoPromise } from './promise';\n\nconst dispatchedErrors = [];\nconst possiblyUnhandledPromiseHandlers : Array<(mixed, promise? : ZalgoPromise) => void> = [];\n\nexport function dispatchPossiblyUnhandledError(err : mixed, promise : ZalgoPromise) {\n\n if (dispatchedErrors.indexOf(err) !== -1) {\n return;\n }\n\n dispatchedErrors.push(err);\n\n setTimeout(() => {\n if (__DEBUG__) {\n // $FlowFixMe\n throw new Error(`${ err.stack || err.toString() }\\n\\nFrom promise:\\n\\n${ promise.stack }`);\n }\n\n throw err;\n }, 1);\n\n for (let j = 0; j < possiblyUnhandledPromiseHandlers.length; j++) {\n // $FlowFixMe\n possiblyUnhandledPromiseHandlers[j](err, promise);\n }\n}\n\nexport function onPossiblyUnhandledException(handler : (mixed, promise? : ZalgoPromise) => void) : {| cancel : () => void |} {\n possiblyUnhandledPromiseHandlers.push(handler);\n\n return {\n cancel() {\n possiblyUnhandledPromiseHandlers.splice(possiblyUnhandledPromiseHandlers.indexOf(handler), 1);\n }\n };\n}\n","/* @flow */\n\nimport type { ZalgoPromise } from './promise';\n\nlet activeCount = 0;\nlet flushPromise;\n\nfunction flushActive() {\n if (!activeCount && flushPromise) {\n const promise = flushPromise;\n flushPromise = null;\n promise.resolve();\n }\n}\n\nexport function startActive() {\n activeCount += 1;\n}\n\nexport function endActive() {\n activeCount -= 1;\n flushActive();\n}\n\nexport function awaitActive(Zalgo : Class>) : ZalgoPromise { // eslint-disable-line no-undef\n const promise = flushPromise = flushPromise || new Zalgo();\n flushActive();\n return promise;\n}\n","/* @flow */\n\nimport { isPromise } from './utils';\nimport { onPossiblyUnhandledException, dispatchPossiblyUnhandledError } from './exceptions';\nimport { startActive, endActive, awaitActive } from './flush';\n\nexport class ZalgoPromise {\n\n resolved : boolean\n rejected : boolean\n errorHandled : boolean\n value : R\n error : mixed\n // eslint-disable-next-line flowtype/no-mutable-array\n handlers : Array<{|\n promise : ZalgoPromise<*>,\n onSuccess : void | (result : R) => mixed,\n onError : void | (error : mixed) => mixed\n |}>\n dispatching : boolean\n stack : string\n\n constructor(handler : ?(resolve : (result : R) => void, reject : (error : mixed) => void) => void) {\n\n this.resolved = false;\n this.rejected = false;\n this.errorHandled = false;\n\n this.handlers = [];\n\n if (handler) {\n\n let result;\n let error;\n let resolved = false;\n let rejected = false;\n let isAsync = false;\n\n startActive();\n\n try {\n handler(res => {\n if (isAsync) {\n this.resolve(res);\n } else {\n resolved = true;\n result = res;\n }\n\n }, err => {\n if (isAsync) {\n this.reject(err);\n } else {\n rejected = true;\n error = err;\n }\n });\n\n } catch (err) {\n endActive();\n this.reject(err);\n return;\n }\n\n endActive();\n\n isAsync = true;\n\n if (resolved) {\n // $FlowFixMe\n this.resolve(result);\n } else if (rejected) {\n this.reject(error);\n }\n }\n\n if (__DEBUG__) {\n try {\n throw new Error(`ZalgoPromise`);\n } catch (err) {\n this.stack = err.stack;\n }\n }\n }\n\n resolve(result : R) : ZalgoPromise {\n if (this.resolved || this.rejected) {\n return this;\n }\n\n if (isPromise(result)) {\n throw new Error('Can not resolve promise with another promise');\n }\n\n this.resolved = true;\n this.value = result;\n this.dispatch();\n\n return this;\n }\n\n reject(error : mixed) : ZalgoPromise {\n if (this.resolved || this.rejected) {\n return this;\n }\n\n if (isPromise(error)) {\n throw new Error('Can not reject promise with another promise');\n }\n\n if (!error) {\n // $FlowFixMe\n const err = (error && typeof error.toString === 'function' ? error.toString() : Object.prototype.toString.call(error));\n error = new Error(`Expected reject to be called with Error, got ${ err }`);\n }\n\n this.rejected = true;\n this.error = error;\n\n if (!this.errorHandled) {\n setTimeout(() => {\n if (!this.errorHandled) {\n dispatchPossiblyUnhandledError(error, this);\n }\n }, 1);\n }\n\n this.dispatch();\n\n return this;\n }\n\n asyncReject(error : mixed) : ZalgoPromise {\n this.errorHandled = true;\n this.reject(error);\n return this;\n }\n \n dispatch() {\n\n const { dispatching, resolved, rejected, handlers } = this;\n\n if (dispatching) {\n return;\n }\n\n if (!resolved && !rejected) {\n return;\n }\n\n this.dispatching = true;\n startActive();\n\n const chain = (firstPromise : ZalgoPromise, secondPromise : ZalgoPromise) => {\n return firstPromise.then(res => {\n secondPromise.resolve(res);\n }, err => {\n secondPromise.reject(err);\n });\n };\n\n for (let i = 0; i < handlers.length; i++) {\n\n const { onSuccess, onError, promise } = handlers[i];\n\n let result;\n\n if (resolved) {\n\n try {\n result = onSuccess ? onSuccess(this.value) : this.value;\n } catch (err) {\n promise.reject(err);\n continue;\n }\n\n } else if (rejected) {\n\n if (!onError) {\n promise.reject(this.error);\n continue;\n }\n\n try {\n result = onError(this.error);\n } catch (err) {\n promise.reject(err);\n continue;\n }\n }\n\n if (result instanceof ZalgoPromise && (result.resolved || result.rejected)) {\n\n if (result.resolved) {\n promise.resolve(result.value);\n } else {\n promise.reject(result.error);\n }\n\n result.errorHandled = true;\n\n } else if (isPromise(result)) {\n\n if (result instanceof ZalgoPromise && (result.resolved || result.rejected)) {\n if (result.resolved) {\n promise.resolve(result.value);\n } else {\n promise.reject(result.error);\n }\n\n } else {\n // $FlowFixMe\n chain(result, promise);\n }\n\n } else {\n\n promise.resolve(result);\n }\n }\n\n handlers.length = 0;\n this.dispatching = false;\n endActive();\n }\n\n then(onSuccess : void | (result : R) => (ZalgoPromise | Y), onError : void | (error : mixed) => (ZalgoPromise | Y)) : ZalgoPromise {\n\n if (onSuccess && typeof onSuccess !== 'function' && !onSuccess.call) {\n throw new Error('Promise.then expected a function for success handler');\n }\n\n if (onError && typeof onError !== 'function' && !onError.call) {\n throw new Error('Promise.then expected a function for error handler');\n }\n\n const promise : ZalgoPromise = new ZalgoPromise();\n\n this.handlers.push({\n promise,\n onSuccess,\n onError\n });\n\n this.errorHandled = true;\n\n this.dispatch();\n\n return promise;\n }\n\n catch(onError : (error : mixed) => ZalgoPromise | Y) : ZalgoPromise {\n return this.then(undefined, onError);\n }\n\n finally(onFinally : () => mixed) : ZalgoPromise {\n\n if (onFinally && typeof onFinally !== 'function' && !onFinally.call) {\n throw new Error('Promise.finally expected a function');\n }\n\n return this.then((result) => {\n return ZalgoPromise.try(onFinally)\n .then(() => {\n return result;\n });\n }, (err) => {\n return ZalgoPromise.try(onFinally)\n .then(() => {\n throw err;\n });\n });\n }\n\n timeout(time : number, err : ?Error) : ZalgoPromise {\n\n if (this.resolved || this.rejected) {\n return this;\n }\n\n const timeout = setTimeout(() => {\n\n if (this.resolved || this.rejected) {\n return;\n }\n\n this.reject(err || new Error(`Promise timed out after ${ time }ms`));\n\n }, time);\n\n return this.then(result => {\n clearTimeout(timeout);\n return result;\n });\n }\n\n // $FlowFixMe\n toPromise() : Promise {\n // $FlowFixMe\n if (typeof Promise === 'undefined') {\n throw new TypeError(`Could not find Promise`);\n }\n // $FlowFixMe\n return Promise.resolve(this); // eslint-disable-line compat/compat\n }\n\n static resolve(value : X | ZalgoPromise) : ZalgoPromise {\n\n if (value instanceof ZalgoPromise) {\n return value;\n }\n\n if (isPromise(value)) {\n // $FlowFixMe\n return new ZalgoPromise((resolve, reject) => value.then(resolve, reject));\n }\n\n return new ZalgoPromise().resolve(value);\n }\n\n static reject(error : mixed) : ZalgoPromise {\n return new ZalgoPromise().reject(error);\n }\n\n static asyncReject(error : mixed) : ZalgoPromise {\n return new ZalgoPromise().asyncReject(error);\n }\n\n static all>(promises : X) : ZalgoPromise<$TupleMap(ZalgoPromise | Y) => Y>> { // eslint-disable-line no-undef\n\n const promise = new ZalgoPromise();\n let count = promises.length;\n const results = [];\n\n if (!count) {\n promise.resolve(results);\n return promise;\n }\n\n const chain = (i : number, firstPromise : ZalgoPromise, secondPromise : ZalgoPromise) => {\n return firstPromise.then(res => {\n results[i] = res;\n count -= 1;\n if (count === 0) {\n promise.resolve(results);\n }\n }, err => {\n secondPromise.reject(err);\n });\n };\n\n for (let i = 0; i < promises.length; i++) {\n const prom = promises[i];\n\n if (prom instanceof ZalgoPromise) {\n if (prom.resolved) {\n results[i] = prom.value;\n count -= 1;\n continue;\n }\n } else if (!isPromise(prom)) {\n results[i] = prom;\n count -= 1;\n continue;\n }\n\n chain(i, ZalgoPromise.resolve(prom), promise);\n }\n\n if (count === 0) {\n promise.resolve(results);\n }\n\n return promise;\n }\n\n static hash(promises : O) : ZalgoPromise<$ObjMap(ZalgoPromise | Y) => Y>> { // eslint-disable-line no-undef\n const result = {};\n const awaitPromises = [];\n\n for (const key in promises) {\n if (promises.hasOwnProperty(key)) {\n const value = promises[key];\n\n if (isPromise(value)) {\n awaitPromises.push(value.then(res => {\n result[key] = res;\n }));\n } else {\n result[key] = value;\n }\n }\n }\n \n return ZalgoPromise.all(awaitPromises).then(() => result);\n }\n\n static map(items : $ReadOnlyArray, method : (T) => (ZalgoPromise | X)) : ZalgoPromise<$ReadOnlyArray> {\n // $FlowFixMe\n return ZalgoPromise.all(items.map(method));\n }\n\n static onPossiblyUnhandledException(handler : (err : mixed) => void) : {| cancel : () => void |} {\n return onPossiblyUnhandledException(handler);\n }\n\n static try>(method : (...args : A) => (ZalgoPromise | Y), context : ?C, args : ?A) : ZalgoPromise {\n\n if (method && typeof method !== 'function' && !method.call) {\n throw new Error('Promise.try expected a function');\n }\n\n let result;\n\n startActive();\n \n try {\n // $FlowFixMe\n result = method.apply(context, args || []);\n } catch (err) {\n endActive();\n return ZalgoPromise.reject(err);\n }\n\n endActive();\n\n return ZalgoPromise.resolve(result);\n }\n\n static delay(delay : number) : ZalgoPromise {\n return new ZalgoPromise(resolve => {\n setTimeout(resolve, delay);\n });\n }\n\n static isPromise(value : mixed) : boolean {\n\n if (value && value instanceof ZalgoPromise) {\n return true;\n }\n\n return isPromise(value);\n }\n\n static flush() : ZalgoPromise {\n return awaitActive(ZalgoPromise);\n }\n}\n","/* @flow */\n/* eslint max-lines: 0 */\n\nimport { isRegex, noop } from './util';\nimport type { CrossDomainWindowType, SameDomainWindowType, DomainMatcher } from './types';\nimport { PROTOCOL, WILDCARD } from './constants';\n\nconst IE_WIN_ACCESS_ERROR = 'Call was rejected by callee.\\r\\n';\n\nexport function isFileProtocol(win : SameDomainWindowType = window) : boolean {\n return win.location.protocol === PROTOCOL.FILE;\n}\n\nexport function isAboutProtocol(win : SameDomainWindowType = window) : boolean {\n return win.location.protocol === PROTOCOL.ABOUT;\n}\n\nexport function getParent(win? : CrossDomainWindowType = window) : ?CrossDomainWindowType {\n\n if (!win) {\n return;\n }\n\n try {\n if (win.parent && win.parent !== win) {\n return win.parent;\n }\n } catch (err) {\n // pass\n }\n}\n\nexport function getOpener(win? : CrossDomainWindowType = window) : ?CrossDomainWindowType {\n\n if (!win) {\n return;\n }\n\n // Make sure we're not actually an iframe which has had window.open() called on us\n if (getParent(win)) {\n return;\n }\n\n try {\n return win.opener;\n } catch (err) {\n // pass\n }\n}\n\nexport function canReadFromWindow(win : CrossDomainWindowType | SameDomainWindowType) : boolean {\n try {\n // $FlowFixMe\n noop(win && win.location && win.location.href);\n return true;\n } catch (err) {\n // pass\n }\n\n return false;\n}\n\nexport function getActualDomain(win? : SameDomainWindowType = window) : string {\n\n const location = win.location;\n\n if (!location) {\n throw new Error(`Can not read window location`);\n }\n\n const protocol = location.protocol;\n\n if (!protocol) {\n throw new Error(`Can not read window protocol`);\n }\n\n if (protocol === PROTOCOL.FILE) {\n return `${ PROTOCOL.FILE }//`;\n }\n\n if (protocol === PROTOCOL.ABOUT) {\n\n const parent = getParent(win);\n if (parent && canReadFromWindow(parent)) {\n // $FlowFixMe\n return getActualDomain(parent);\n }\n\n return `${ PROTOCOL.ABOUT }//`;\n }\n\n const host = location.host;\n\n if (!host) {\n throw new Error(`Can not read window host`);\n }\n\n return `${ protocol }//${ host }`;\n}\n\nexport function getDomain(win? : SameDomainWindowType = window) : string {\n\n const domain = getActualDomain(win);\n\n if (domain && win.mockDomain && win.mockDomain.indexOf(PROTOCOL.MOCK) === 0) {\n return win.mockDomain;\n }\n\n return domain;\n}\n\nexport function isBlankDomain(win : CrossDomainWindowType) : boolean {\n try {\n // $FlowFixMe\n if (!win.location.href) {\n return true;\n }\n\n if (win.location.href === 'about:blank') {\n return true;\n }\n } catch (err) {\n // pass\n }\n\n return false;\n}\n\nexport function isActuallySameDomain(win : CrossDomainWindowType) : boolean {\n\n try {\n if (win === window) {\n return true;\n }\n\n } catch (err) {\n // pass\n }\n\n try {\n const desc = Object.getOwnPropertyDescriptor(win, 'location');\n\n if (desc && desc.enumerable === false) {\n return false;\n }\n\n } catch (err) {\n // pass\n }\n\n try {\n // $FlowFixMe\n if (isAboutProtocol(win) && canReadFromWindow(win)) {\n return true;\n }\n } catch (err) {\n // pass\n }\n\n try {\n // $FlowFixMe\n if (getActualDomain(win) === getActualDomain(window)) {\n return true;\n }\n\n } catch (err) {\n // pass\n }\n\n return false;\n}\n\nexport function isSameDomain(win : CrossDomainWindowType | SameDomainWindowType) : boolean {\n\n if (!isActuallySameDomain(win)) {\n return false;\n }\n\n try {\n\n if (win === window) {\n return true;\n }\n\n // $FlowFixMe\n if (isAboutProtocol(win) && canReadFromWindow(win)) {\n return true;\n }\n\n // $FlowFixMe\n if (getDomain(window) === getDomain(win)) {\n return true;\n }\n\n } catch (err) {\n // pass\n }\n\n return false;\n}\n\n\nexport function assertSameDomain(win : CrossDomainWindowType | SameDomainWindowType) : SameDomainWindowType {\n if (!isSameDomain(win)) {\n throw new Error(`Expected window to be same domain`);\n }\n\n // $FlowFixMe\n return win;\n}\n\nexport function getParents(win : CrossDomainWindowType) : $ReadOnlyArray {\n\n const result = [];\n\n try {\n\n while (win.parent !== win) {\n result.push(win.parent);\n win = win.parent;\n }\n\n } catch (err) {\n // pass\n }\n\n return result;\n}\n\nexport function isAncestorParent(parent : CrossDomainWindowType, child : CrossDomainWindowType) : boolean {\n\n if (!parent || !child) {\n return false;\n }\n\n const childParent = getParent(child);\n\n if (childParent) {\n return childParent === parent;\n }\n\n if (getParents(child).indexOf(parent) !== -1) {\n return true;\n }\n\n return false;\n}\n\nexport function getFrames(win : CrossDomainWindowType) : $ReadOnlyArray {\n\n const result = [];\n\n let frames;\n\n try {\n frames = win.frames;\n } catch (err) {\n frames = win;\n }\n\n let len;\n\n try {\n len = frames.length;\n } catch (err) {\n // pass\n }\n\n if (len === 0) {\n return result;\n }\n\n if (len) {\n for (let i = 0; i < len; i++) {\n\n let frame;\n\n try {\n frame = frames[i];\n } catch (err) {\n continue;\n }\n\n result.push(frame);\n }\n\n return result;\n }\n\n for (let i = 0; i < 100; i++) {\n let frame;\n\n try {\n frame = frames[i];\n } catch (err) {\n return result;\n }\n\n if (!frame) {\n return result;\n }\n\n result.push(frame);\n }\n\n return result;\n}\n\n\nexport function getAllChildFrames(win : CrossDomainWindowType) : $ReadOnlyArray {\n\n const result = [];\n\n for (const frame of getFrames(win)) {\n result.push(frame);\n\n for (const childFrame of getAllChildFrames(frame)) {\n result.push(childFrame);\n }\n }\n\n return result;\n}\n\nexport function getTop(win? : CrossDomainWindowType = window) : ?CrossDomainWindowType {\n\n try {\n if (win.top) {\n return win.top;\n }\n } catch (err) {\n // pass\n }\n\n if (getParent(win) === win) {\n return win;\n }\n\n try {\n if (isAncestorParent(window, win) && window.top) {\n return window.top;\n }\n } catch (err) {\n // pass\n }\n\n try {\n if (isAncestorParent(win, window) && window.top) {\n return window.top;\n }\n } catch (err) {\n // pass\n }\n\n for (const frame of getAllChildFrames(win)) {\n try {\n if (frame.top) {\n return frame.top;\n }\n } catch (err) {\n // pass\n }\n\n if (getParent(frame) === frame) {\n return frame;\n }\n }\n}\n\nexport function getNextOpener(win? : CrossDomainWindowType = window) : ?CrossDomainWindowType {\n return getOpener(getTop(win) || win);\n}\n\nexport function getUltimateTop(win? : CrossDomainWindowType = window) : CrossDomainWindowType {\n const opener = getNextOpener(win);\n\n if (opener) {\n return getUltimateTop(opener);\n }\n\n return top;\n}\n\nexport function getAllFramesInWindow(win : CrossDomainWindowType) : $ReadOnlyArray {\n const top = getTop(win);\n\n if (!top) {\n throw new Error(`Can not determine top window`);\n }\n\n let result = [ ...getAllChildFrames(top), top ];\n\n // Win may be in shadow dom\n if (result.indexOf(win) === -1) {\n result = [ ...result, win, ...getAllChildFrames(win) ];\n }\n\n return result;\n}\n\nexport function getAllWindows(win? : CrossDomainWindowType = window) : $ReadOnlyArray {\n const frames = getAllFramesInWindow(win);\n const opener = getNextOpener(win);\n\n if (opener) {\n return [ ...getAllWindows(opener), ...frames ];\n } else {\n return frames;\n }\n}\n\nexport function isTop(win : CrossDomainWindowType) : boolean {\n return win === getTop(win);\n}\n\nexport function isFrameWindowClosed(frame : HTMLIFrameElement) : boolean {\n\n if (!frame.contentWindow) {\n return true;\n }\n\n if (!frame.parentNode) {\n return true;\n }\n\n const doc = frame.ownerDocument;\n\n if (doc && doc.documentElement && !doc.documentElement.contains(frame)) {\n let parent = frame;\n\n while (parent.parentNode && parent.parentNode !== parent) {\n parent = parent.parentNode;\n }\n\n // $FlowFixMe\n if (!parent.host || !doc.documentElement.contains(parent.host)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction safeIndexOf(collection : $ReadOnlyArray, item : T) : number {\n for (let i = 0; i < collection.length; i++) {\n\n try {\n if (collection[i] === item) {\n return i;\n }\n } catch (err) {\n // pass\n }\n }\n\n return -1;\n}\n\nconst iframeWindows = [];\nconst iframeFrames = [];\n\nexport function isWindowClosed(win : CrossDomainWindowType, allowMock : boolean = true) : boolean {\n\n try {\n if (win === window) {\n return false;\n }\n } catch (err) {\n return true;\n }\n\n try {\n if (!win) {\n return true;\n }\n\n } catch (err) {\n return true;\n }\n\n try {\n if (win.closed) {\n return true;\n }\n\n } catch (err) {\n\n // I love you so much IE\n\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return false;\n }\n\n return true;\n }\n\n\n if (allowMock && isSameDomain(win)) {\n try {\n // $FlowFixMe\n if (win.mockclosed) {\n return true;\n }\n } catch (err) {\n // pass\n }\n }\n\n // Mobile safari\n\n try {\n if (!win.parent || !win.top) {\n return true;\n }\n } catch (err) {\n // pass\n }\n\n // Yes, this actually happens in IE. win === win errors out when the window\n // is from an iframe, and the iframe was removed from the page.\n\n try {\n noop(win === win); // eslint-disable-line no-self-compare\n } catch (err) {\n return true;\n }\n\n // IE orphaned frame\n\n const iframeIndex = safeIndexOf(iframeWindows, win);\n\n if (iframeIndex !== -1) {\n const frame = iframeFrames[iframeIndex];\n\n if (frame && isFrameWindowClosed(frame)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction cleanIframes() {\n for (let i = 0; i < iframeWindows.length; i++) {\n let closed = false;\n\n try {\n closed = iframeWindows[i].closed;\n } catch (err) {\n // pass\n }\n\n if (closed) {\n iframeFrames.splice(i, 1);\n iframeWindows.splice(i, 1);\n }\n }\n}\n\nexport function linkFrameWindow(frame : HTMLIFrameElement) {\n\n cleanIframes();\n\n if (frame && frame.contentWindow) {\n try {\n iframeWindows.push(frame.contentWindow);\n iframeFrames.push(frame);\n } catch (err) {\n // pass\n }\n }\n}\n\nexport function getUserAgent(win : ?SameDomainWindowType) : string {\n win = win || window;\n return win.navigator.mockUserAgent || win.navigator.userAgent;\n}\n\n\nexport function getFrameByName(win : CrossDomainWindowType, name : string) : ?CrossDomainWindowType {\n\n const winFrames = getFrames(win);\n\n for (const childFrame of winFrames) {\n try {\n // $FlowFixMe\n if (isSameDomain(childFrame) && childFrame.name === name && winFrames.indexOf(childFrame) !== -1) {\n return childFrame;\n }\n } catch (err) {\n // pass\n }\n }\n\n try {\n // $FlowFixMe\n if (winFrames.indexOf(win.frames[name]) !== -1) {\n // $FlowFixMe\n return win.frames[name];\n }\n } catch (err) {\n // pass\n }\n\n try {\n if (winFrames.indexOf(win[name]) !== -1) {\n return win[name];\n }\n } catch (err) {\n // pass\n }\n}\n\nexport function findChildFrameByName(win : CrossDomainWindowType, name : string) : ?CrossDomainWindowType {\n\n const frame = getFrameByName(win, name);\n\n if (frame) {\n return frame;\n }\n\n for (const childFrame of getFrames(win)) {\n const namedFrame = findChildFrameByName(childFrame, name);\n\n if (namedFrame) {\n return namedFrame;\n }\n }\n}\n\nexport function findFrameByName(win : CrossDomainWindowType, name : string) : ?CrossDomainWindowType {\n const frame = getFrameByName(win, name);\n\n if (frame) {\n return frame;\n }\n\n const top = getTop(win) || win;\n\n return findChildFrameByName(top, name);\n}\n\nexport function isParent(win : CrossDomainWindowType, frame : CrossDomainWindowType) : boolean {\n\n const frameParent = getParent(frame);\n\n if (frameParent) {\n return frameParent === win;\n }\n\n for (const childFrame of getFrames(win)) {\n if (childFrame === frame) {\n return true;\n }\n }\n\n return false;\n}\n\nexport function isOpener(parent : CrossDomainWindowType, child : CrossDomainWindowType) : boolean {\n\n return parent === getOpener(child);\n}\n\nexport function getAncestor(win? : CrossDomainWindowType = window) : ?CrossDomainWindowType {\n win = win || window;\n\n const opener = getOpener(win);\n\n if (opener) {\n return opener;\n }\n\n const parent = getParent(win);\n\n if (parent) {\n return parent;\n }\n}\n\nexport function getAncestors(win : CrossDomainWindowType) : $ReadOnlyArray {\n\n const results = [];\n\n let ancestor = win;\n\n while (ancestor) {\n ancestor = getAncestor(ancestor);\n if (ancestor) {\n results.push(ancestor);\n }\n }\n\n return results;\n}\n\n\nexport function isAncestor(parent : CrossDomainWindowType, child : CrossDomainWindowType) : boolean {\n\n const actualParent = getAncestor(child);\n\n if (actualParent) {\n if (actualParent === parent) {\n return true;\n }\n\n return false;\n }\n\n if (child === parent) {\n return false;\n }\n\n if (getTop(child) === child) {\n return false;\n }\n\n for (const frame of getFrames(parent)) {\n if (frame === child) {\n return true;\n }\n }\n\n return false;\n}\n\nexport function isPopup(win? : CrossDomainWindowType = window) : boolean {\n return Boolean(getOpener(win));\n}\n\nexport function isIframe(win? : CrossDomainWindowType = window) : boolean {\n return Boolean(getParent(win));\n}\n\nexport function isFullpage(win? : CrossDomainWindowType = window) : boolean {\n return Boolean(!isIframe(win) && !isPopup(win));\n}\n\nfunction anyMatch(collection1, collection2) : boolean {\n\n for (const item1 of collection1) {\n for (const item2 of collection2) {\n if (item1 === item2) {\n return true;\n }\n }\n }\n\n return false;\n}\n\nexport function getDistanceFromTop(win : CrossDomainWindowType = window) : number {\n let distance = 0;\n let parent = win;\n\n while (parent) {\n parent = getParent(parent);\n if (parent) {\n distance += 1;\n }\n }\n\n return distance;\n}\n\nexport function getNthParent(win : CrossDomainWindowType, n : number = 1) : ?CrossDomainWindowType {\n let parent = win;\n\n for (let i = 0; i < n; i++) {\n if (!parent) {\n return;\n }\n\n parent = getParent(parent);\n }\n\n return parent;\n}\n\nexport function getNthParentFromTop(win : CrossDomainWindowType, n : number = 1) : ?CrossDomainWindowType {\n return getNthParent(win, getDistanceFromTop(win) - n);\n}\n\nexport function isSameTopWindow(win1 : CrossDomainWindowType, win2 : CrossDomainWindowType) : boolean {\n\n const top1 = getTop(win1) || win1;\n const top2 = getTop(win2) || win2;\n\n try {\n if (top1 && top2) {\n if (top1 === top2) {\n return true;\n }\n\n return false;\n }\n } catch (err) {\n // pass\n }\n\n const allFrames1 = getAllFramesInWindow(win1);\n const allFrames2 = getAllFramesInWindow(win2);\n\n if (anyMatch(allFrames1, allFrames2)) {\n return true;\n }\n\n const opener1 = getOpener(top1);\n const opener2 = getOpener(top2);\n\n if (opener1 && anyMatch(getAllFramesInWindow(opener1), allFrames2)) {\n return false;\n }\n\n if (opener2 && anyMatch(getAllFramesInWindow(opener2), allFrames1)) {\n return false;\n }\n\n return false;\n}\n\nexport function matchDomain(pattern : DomainMatcher, origin : DomainMatcher) : boolean {\n\n if (typeof pattern === 'string') {\n\n if (typeof origin === 'string') {\n return pattern === WILDCARD || origin === pattern;\n }\n\n if (isRegex(origin)) {\n return false;\n }\n\n if (Array.isArray(origin)) {\n return false;\n }\n }\n\n if (isRegex(pattern)) {\n\n if (isRegex(origin)) {\n return pattern.toString() === origin.toString();\n }\n\n if (Array.isArray(origin)) {\n return false;\n }\n\n // $FlowFixMe\n return Boolean(origin.match(pattern));\n }\n\n if (Array.isArray(pattern)) {\n\n if (Array.isArray(origin)) {\n return JSON.stringify(pattern) === JSON.stringify(origin);\n }\n\n if (isRegex(origin)) {\n return false;\n }\n\n return pattern.some(subpattern => matchDomain(subpattern, origin));\n }\n\n return false;\n}\n\nexport function stringifyDomainPattern(pattern : DomainMatcher) : string {\n if (Array.isArray(pattern)) {\n return `(${ pattern.join(' | ') })`;\n } else if (isRegex(pattern)) {\n return `RegExp(${ pattern.toString() }`;\n } else {\n return pattern.toString();\n }\n}\n\nexport function getDomainFromUrl(url : string) : string {\n\n let domain;\n\n if (url.match(/^(https?|mock|file):\\/\\//)) {\n domain = url;\n } else {\n return getDomain();\n }\n\n domain = domain.split('/').slice(0, 3).join('/');\n\n return domain;\n}\n\nexport function onCloseWindow(win : CrossDomainWindowType, callback : Function, delay : number = 1000, maxtime : number = Infinity) : {| cancel : () => void |} {\n\n let timeout;\n\n const check = () => {\n\n if (isWindowClosed(win)) {\n\n if (timeout) {\n clearTimeout(timeout);\n }\n\n return callback();\n }\n\n if (maxtime <= 0) {\n clearTimeout(timeout);\n } else {\n maxtime -= delay;\n timeout = setTimeout(check, delay);\n }\n };\n\n check();\n\n return {\n cancel() {\n if (timeout) {\n clearTimeout(timeout);\n }\n }\n };\n}\n\n// eslint-disable-next-line complexity\nexport function isWindow(obj : Object) : boolean {\n\n try {\n if (obj === window) {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (Object.prototype.toString.call(obj) === '[object Window]') {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (window.Window && obj instanceof window.Window) {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (obj && obj.self === obj) {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (obj && obj.parent === obj) {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (obj && obj.top === obj) {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (noop(obj === obj) === '__unlikely_value__') { // eslint-disable-line no-self-compare\n return false;\n }\n\n } catch (err) {\n return true;\n }\n\n try {\n if (obj && obj.__cross_domain_utils_window_check__ === '__unlikely_value__') {\n return false;\n }\n\n } catch (err) {\n return true;\n }\n\n try {\n if ('postMessage' in obj && 'self' in obj && 'location' in obj) {\n return true;\n }\n } catch (err) {\n // pass\n }\n\n return false;\n}\n\nexport function isBrowser() : boolean {\n return (typeof window !== 'undefined' && typeof window.location !== 'undefined');\n}\n\nexport function isCurrentDomain(domain : string) : boolean {\n if (!isBrowser()) {\n return false;\n }\n\n return (getDomain() === domain);\n}\n\nexport function isMockDomain(domain : string) : boolean {\n return domain.indexOf(PROTOCOL.MOCK) === 0;\n}\n\nexport function normalizeMockUrl(url : string) : string {\n if (!isMockDomain(getDomainFromUrl(url))) {\n return url;\n }\n\n if (!__TEST__) {\n throw new Error(`Mock urls not supported out of test mode`);\n }\n\n return url.replace(/^mock:\\/\\/[^/]+/, getActualDomain(window));\n}\n\nexport function closeWindow(win : CrossDomainWindowType) {\n try {\n win.close();\n } catch (err) {\n // pass\n }\n}\n\nexport function getFrameForWindow(win : CrossDomainWindowType) : ?HTMLElement {\n if (isSameDomain(win)) {\n return assertSameDomain(win).frameElement;\n }\n\n for (const frame of document.querySelectorAll('iframe')) {\n if (frame && frame.contentWindow && frame.contentWindow === win) {\n return frame;\n }\n }\n}\n","/* @flow */\n\nexport const PROTOCOL = {\n MOCK: ('mock:' : 'mock:'),\n FILE: ('file:' : 'file:'),\n ABOUT: ('about:' : 'about:')\n};\n\nexport const WILDCARD = '*';\n\nexport const WINDOW_TYPE = {\n IFRAME: ('iframe' : 'iframe'),\n POPUP: ('popup' : 'popup')\n};\n","/* @flow */\n\nexport function safeIndexOf(collection : $ReadOnlyArray, item : T) : number {\n for (let i = 0; i < collection.length; i++) {\n\n try {\n if (collection[i] === item) {\n return i;\n }\n } catch (err) {\n // pass\n }\n }\n\n return -1;\n}\n\n// eslint-disable-next-line no-unused-vars\nexport function noop(...args : $ReadOnlyArray) {\n // pass\n}\n","/* @flow */\n\nimport { isWindow, isWindowClosed } from 'cross-domain-utils/src';\n\nimport { hasNativeWeakMap } from './native';\nimport { noop, safeIndexOf } from './util';\n\nexport class CrossDomainSafeWeakMap {\n\n name : string\n weakmap : ?WeakMap\n // eslint-disable-next-line flowtype/no-mutable-array\n keys : Array\n // eslint-disable-next-line flowtype/no-mutable-array\n values : Array\n\n constructor() {\n // eslint-disable-next-line no-bitwise\n this.name = `__weakmap_${ Math.random() * 1e9 >>> 0 }__`;\n\n if (hasNativeWeakMap()) {\n try {\n this.weakmap = new WeakMap();\n } catch (err) {\n // pass\n }\n }\n\n this.keys = [];\n this.values = [];\n }\n\n _cleanupClosedWindows() {\n\n const weakmap = this.weakmap;\n const keys = this.keys;\n\n for (let i = 0; i < keys.length; i++) {\n const value = keys[i];\n\n if (isWindow(value) && isWindowClosed(value)) {\n\n if (weakmap) {\n try {\n weakmap.delete(value);\n } catch (err) {\n // pass\n }\n }\n\n keys.splice(i, 1);\n this.values.splice(i, 1);\n\n i -= 1;\n }\n }\n }\n\n isSafeToReadWrite(key : K) : boolean {\n\n if (isWindow(key)) {\n return false;\n }\n\n try {\n noop(key && key.self);\n noop(key && key[this.name]);\n } catch (err) {\n return false;\n }\n\n return true;\n }\n\n set(key : K, value : V) {\n\n if (!key) {\n throw new Error(`WeakMap expected key`);\n }\n\n const weakmap = this.weakmap;\n\n if (weakmap) {\n try {\n weakmap.set(key, value);\n } catch (err) {\n delete this.weakmap;\n }\n }\n\n if (this.isSafeToReadWrite(key)) {\n try {\n const name = this.name;\n const entry = key[name];\n\n if (entry && entry[0] === key) {\n entry[1] = value;\n } else {\n Object.defineProperty(key, name, {\n value: [ key, value ],\n writable: true\n });\n }\n\n return;\n\n } catch (err) {\n // pass\n }\n }\n\n this._cleanupClosedWindows();\n\n const keys = this.keys;\n const values = this.values;\n const index = safeIndexOf(keys, key);\n\n if (index === -1) {\n keys.push(key);\n values.push(value);\n } else {\n values[index] = value;\n }\n }\n\n get(key : K) : V | void {\n\n if (!key) {\n throw new Error(`WeakMap expected key`);\n }\n\n const weakmap = this.weakmap;\n\n if (weakmap) {\n try {\n if (weakmap.has(key)) {\n return weakmap.get(key);\n }\n \n } catch (err) {\n delete this.weakmap;\n }\n }\n\n if (this.isSafeToReadWrite(key)) {\n try {\n const entry = key[this.name];\n\n if (entry && entry[0] === key) {\n return entry[1];\n }\n\n return;\n } catch (err) {\n // pass\n }\n }\n\n this._cleanupClosedWindows();\n\n const keys = this.keys;\n const index = safeIndexOf(keys, key);\n\n if (index === -1) {\n return;\n }\n\n return this.values[index];\n }\n\n delete(key : K) {\n\n if (!key) {\n throw new Error(`WeakMap expected key`);\n }\n\n const weakmap = this.weakmap;\n\n if (weakmap) {\n try {\n weakmap.delete(key);\n } catch (err) {\n delete this.weakmap;\n }\n }\n\n if (this.isSafeToReadWrite(key)) {\n try {\n const entry = key[this.name];\n\n if (entry && entry[0] === key) {\n entry[0] = entry[1] = undefined;\n }\n } catch (err) {\n // pass\n }\n }\n\n this._cleanupClosedWindows();\n\n const keys = this.keys;\n const index = safeIndexOf(keys, key);\n\n if (index !== -1) {\n keys.splice(index, 1);\n this.values.splice(index, 1);\n }\n }\n\n has(key : K) : boolean {\n\n if (!key) {\n throw new Error(`WeakMap expected key`);\n }\n\n const weakmap = this.weakmap;\n\n if (weakmap) {\n try {\n if (weakmap.has(key)) {\n return true;\n }\n } catch (err) {\n delete this.weakmap;\n }\n }\n\n if (this.isSafeToReadWrite(key)) {\n try {\n const entry = key[this.name];\n\n if (entry && entry[0] === key) {\n return true;\n }\n\n return false;\n } catch (err) {\n // pass\n }\n }\n\n this._cleanupClosedWindows();\n\n const index = safeIndexOf(this.keys, key);\n return index !== -1;\n }\n\n getOrSet(key : K, getter : () => V) : V {\n if (this.has(key)) {\n // $FlowFixMe\n return this.get(key);\n }\n\n const value = getter();\n this.set(key, value);\n return value;\n }\n}\n","\n/* @flow */\n/* eslint max-lines: 0 */\n\nimport { ZalgoPromise } from 'zalgo-promise/src';\nimport { WeakMap } from 'cross-domain-safe-weakmap/src';\n\nimport type { CancelableType } from './types';\n\nexport function getFunctionName (fn : T) : string {\n return fn.name || fn.__name__ || fn.displayName || 'anonymous';\n}\n\nexport function setFunctionName (fn : T, name : string) : T {\n try {\n delete fn.name;\n fn.name = name;\n } catch (err) {\n // pass\n }\n\n fn.__name__ = fn.displayName = name;\n return fn;\n}\n\nexport function base64encode(str : string) : string {\n if (typeof btoa === 'function') {\n return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (m, p1) => {\n return String.fromCharCode(parseInt(p1, 16));\n }));\n }\n\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(str, 'utf8').toString('base64');\n }\n\n throw new Error(`Can not find window.btoa or Buffer`);\n}\n\nexport function base64decode(str : string) : string {\n if (typeof atob === 'function') {\n return decodeURIComponent(Array.prototype.map.call(atob(str), c => {\n // eslint-disable-next-line prefer-template\n return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);\n }).join(''));\n }\n\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(str, 'base64').toString('utf8');\n }\n\n throw new Error(`Can not find window.atob or Buffer`);\n}\n\nexport function uniqueID() : string {\n\n const chars = '0123456789abcdef';\n\n const randomID = 'xxxxxxxxxx'.replace(/./g, () => {\n return chars.charAt(Math.floor(Math.random() * chars.length));\n });\n\n const timeID = base64encode(\n new Date().toISOString().slice(11, 19).replace('T', '.')\n ).replace(/[^a-zA-Z0-9]/g, '').toLowerCase();\n\n return `${ randomID }_${ timeID }`;\n}\n\nexport function getGlobal() : Object {\n if (typeof window !== 'undefined') {\n return window;\n }\n if (typeof global !== 'undefined') {\n return global;\n }\n if (typeof __GLOBAL__ !== 'undefined') {\n return __GLOBAL__;\n }\n throw new Error(`No global found`);\n}\n\nlet objectIDs;\n\nexport function getObjectID(obj : Object) : string {\n\n objectIDs = objectIDs || new WeakMap();\n\n if (obj === null || obj === undefined || (typeof obj !== 'object' && typeof obj !== 'function')) {\n throw new Error(`Invalid object`);\n }\n\n let uid = objectIDs.get(obj);\n\n if (!uid) {\n uid = `${ typeof obj }:${ uniqueID() }`;\n objectIDs.set(obj, uid);\n }\n\n return uid;\n}\n\nfunction serializeArgs(args : $ReadOnlyArray) : string {\n try {\n return JSON.stringify(Array.prototype.slice.call(args), (subkey, val) => {\n if (typeof val === 'function') {\n return `memoize[${ getObjectID(val) }]`;\n }\n return val;\n });\n } catch (err) {\n throw new Error(`Arguments not serializable -- can not be used to memoize`);\n }\n}\ntype MemoizeOptions = {|\n name? : string,\n time? : number,\n thisNamespace? : boolean\n|};\n\nconst getDefaultMemoizeOptions = () : MemoizeOptions => {\n // $FlowFixMe\n return {};\n};\n\nconst memoizedFunctions = [];\n\nexport function memoize(method : F, options? : MemoizeOptions = getDefaultMemoizeOptions()) : F & {| reset : () => void |} {\n const cacheMap = new WeakMap();\n\n const memoizedFunction = function memoizedFunction(...args) : mixed {\n const cache = cacheMap.getOrSet(options.thisNamespace ? this : method, () => ({}));\n\n const key : string = serializeArgs(args);\n\n const cacheTime = options.time;\n if (cache[key] && cacheTime && (Date.now() - cache[key].time) < cacheTime) {\n delete cache[key];\n }\n\n if (cache[key]) {\n return cache[key].value;\n }\n\n const time = Date.now();\n const value = method.apply(this, arguments);\n\n cache[key] = { time, value };\n\n return cache[key].value;\n };\n\n memoizedFunction.reset = () => {\n cacheMap.delete(options.thisNamespace ? this : method);\n };\n\n memoizedFunctions.push(memoizedFunction);\n\n // $FlowFixMe\n const result : F = memoizedFunction;\n\n return setFunctionName(result, `${ options.name || getFunctionName(method) }::memoized`);\n}\n\nmemoize.clear = () => {\n for (const memoizedFunction of memoizedFunctions) {\n memoizedFunction.reset();\n }\n};\n\nexport function promiseIdentity(item : ZalgoPromise | T) : ZalgoPromise {\n // $FlowFixMe\n return ZalgoPromise.resolve(item);\n}\n\n// eslint-disable-next-line flowtype/no-weak-types\nexport function memoizePromise(method : (...args : $ReadOnlyArray) => ZalgoPromise) : ((...args : $ReadOnlyArray) => ZalgoPromise) {\n let cache = {};\n\n // eslint-disable-next-line flowtype/no-weak-types\n function memoizedPromiseFunction(...args : $ReadOnlyArray) : ZalgoPromise {\n const key : string = serializeArgs(args);\n\n if (cache.hasOwnProperty(key)) {\n return cache[key];\n }\n\n cache[key] = ZalgoPromise.try(() => method.apply(this, arguments))\n .finally(() => {\n delete cache[key];\n });\n\n return cache[key];\n }\n\n memoizedPromiseFunction.reset = () => {\n cache = {};\n };\n\n return setFunctionName(memoizedPromiseFunction, `${ getFunctionName(method) }::promiseMemoized`);\n}\n\ntype PromisifyOptions = {|\n name ? : string\n|};\n\nconst getDefaultPromisifyOptions = () : PromisifyOptions => {\n // $FlowFixMe\n return {};\n};\n\n// eslint-disable-next-line flowtype/no-weak-types\nexport function promisify(method : (...args : $ReadOnlyArray) => R, options : PromisifyOptions = getDefaultPromisifyOptions()) : ((...args : $ReadOnlyArray) => ZalgoPromise) {\n function promisifiedFunction() : ZalgoPromise {\n return ZalgoPromise.try(method, this, arguments);\n }\n\n if (options.name) {\n promisifiedFunction.displayName = `${ options.name }:promisified`;\n }\n\n return setFunctionName(promisifiedFunction, `${ getFunctionName(method) }::promisified`);\n}\n\n// eslint-disable-next-line flowtype/no-weak-types\nexport function inlineMemoize(method : (...args : $ReadOnlyArray) => R, logic : (...args : $ReadOnlyArray) => R, args : $ReadOnlyArray = []) : R {\n // $FlowFixMe\n const cache : {| [string] : R |} = method.__inline_memoize_cache__ = method.__inline_memoize_cache__ || {};\n const key = serializeArgs(args);\n\n if (cache.hasOwnProperty(key)) {\n return cache[key];\n }\n \n const result = cache[key] = logic(...args);\n\n return result;\n}\n\n// eslint-disable-next-line no-unused-vars\nexport function noop(...args : $ReadOnlyArray) {\n // pass\n}\n\nexport function once(method : Function) : Function {\n let called = false;\n\n const onceFunction = function() : mixed {\n if (!called) {\n called = true;\n return method.apply(this, arguments);\n }\n };\n\n return setFunctionName(onceFunction, `${ getFunctionName(method) }::once`);\n}\n\nexport function hashStr(str : string) : number {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n hash += str[i].charCodeAt(0) * Math.pow((i % 10) + 1, 5);\n }\n return Math.floor(Math.pow(Math.sqrt(hash), 5));\n}\n\nexport function strHashStr(str : string) : string {\n let hash = '';\n\n for (let i = 0; i < str.length; i++) {\n let total = (str[i].charCodeAt(0) * i);\n\n if (str[i + 1]) {\n total += (str[i + 1].charCodeAt(0) * (i - 1));\n }\n\n hash += String.fromCharCode(97 + (Math.abs(total) % 26));\n }\n\n return hash;\n}\n\nexport function match(str : string, pattern : RegExp) : ?string {\n const regmatch = str.match(pattern);\n if (regmatch) {\n return regmatch[1];\n }\n}\n\nexport function awaitKey(obj : Object, key : string) : ZalgoPromise {\n return new ZalgoPromise(resolve => {\n\n let value = obj[key];\n\n if (value) {\n return resolve(value);\n }\n\n delete obj[key];\n\n Object.defineProperty(obj, key, {\n\n configurable: true,\n\n set(item) {\n value = item;\n\n if (value) {\n resolve(value);\n }\n },\n\n get() : T {\n return value;\n }\n });\n });\n}\n\nexport function stringifyError(err : mixed, level : number = 1) : string {\n\n if (level >= 3) {\n return 'stringifyError stack overflow';\n }\n\n try {\n if (!err) {\n return ``;\n }\n\n if (typeof err === 'string') {\n return err;\n }\n\n if (err instanceof Error) {\n const stack = err && err.stack;\n const message = err && err.message;\n\n if (stack && message) {\n if (stack.indexOf(message) !== -1) {\n return stack;\n } else {\n return `${ message }\\n${ stack }`;\n }\n } else if (stack) {\n return stack;\n } else if (message) {\n return message;\n }\n }\n\n if (err && err.toString && typeof err.toString === 'function') {\n // $FlowFixMe\n return err.toString();\n }\n\n return Object.prototype.toString.call(err);\n\n } catch (newErr) {\n return `Error while stringifying error: ${ stringifyError(newErr, level + 1) }`;\n }\n}\n\nexport function stringifyErrorMessage(err : mixed) : string {\n\n const defaultMessage = ``;\n\n if (!err) {\n return defaultMessage;\n }\n\n if (err instanceof Error) {\n return err.message || defaultMessage;\n }\n\n if (typeof err.message === 'string') {\n return err.message || defaultMessage;\n }\n\n return defaultMessage;\n}\n\nexport function stringify(item : mixed) : string {\n if (typeof item === 'string') {\n return item;\n }\n\n if (item && item.toString && typeof item.toString === 'function') {\n // $FlowFixMe\n return item.toString();\n }\n\n return Object.prototype.toString.call(item);\n}\n\nexport function domainMatches(hostname : string, domain : string) : boolean {\n hostname = hostname.split('://')[1];\n const index = hostname.indexOf(domain);\n return (index !== -1 && hostname.slice(index) === domain);\n}\n\nexport function patchMethod(obj : Object, name : string, handler : Function) {\n const original = obj[name];\n\n obj[name] = function patchedMethod() : mixed {\n return handler({\n context: this,\n args: Array.prototype.slice.call(arguments),\n original,\n callOriginal: () => original.apply(this, arguments)\n });\n };\n}\n\nexport function extend(obj : T, source : Object) : T {\n if (!source) {\n return obj;\n }\n\n if (Object.assign) {\n return Object.assign(obj, source);\n }\n\n for (const key in source) {\n if (source.hasOwnProperty(key)) {\n obj[key] = source[key];\n }\n }\n\n return obj;\n}\n\n// eslint-disable-next-line no-undef\ntype Values = ({ [string] : T }) => $ReadOnlyArray;\n\nexport const values : Values = (obj) => {\n if (Object.values) {\n // $FlowFixMe\n return Object.values(obj);\n }\n\n const result = [];\n for (const key in obj) {\n if (obj.hasOwnProperty(key)) {\n result.push(obj[key]);\n }\n }\n\n // $FlowFixMe\n return result;\n};\n\nexport const memoizedValues : Values = memoize(values);\n\nexport function perc(pixels : number, percentage : number) : number {\n return Math.round((pixels * percentage) / 100);\n}\n\nexport function min(...args : $ReadOnlyArray) : number {\n return Math.min(...args);\n}\n\nexport function max(...args : $ReadOnlyArray) : number {\n return Math.max(...args);\n}\n\nexport function regexMap(str : string, regexp : RegExp, handler : () => T) : $ReadOnlyArray {\n const results = [];\n\n // $FlowFixMe\n str.replace(regexp, function regexMapMatcher(item) {\n results.push(handler ? handler.apply(null, arguments) : item);\n });\n\n // $FlowFixMe\n return results;\n}\n\nexport function svgToBase64(svg : string) : string {\n return `data:image/svg+xml;base64,${ base64encode(svg) }`;\n}\n\nexport function objFilter(obj : { [string] : T }, filter? : (T, ?string) => mixed = Boolean) : { [string] : R } {\n const result = {};\n\n for (const key in obj) {\n if (!obj.hasOwnProperty(key) || !filter(obj[key], key)) {\n continue;\n }\n\n result[key] = obj[key];\n }\n\n return result;\n}\n\nexport function identity (item : T) : T {\n return item;\n}\n\nexport function regexTokenize(text : string, regexp : RegExp) : $ReadOnlyArray {\n const result = [];\n text.replace(regexp, token => {\n result.push(token);\n return '';\n });\n return result;\n}\n\nexport function promiseDebounce(method : () => ZalgoPromise | T, delay : number = 50) : () => ZalgoPromise {\n\n let promise;\n let timeout;\n\n const promiseDebounced = function() : ZalgoPromise {\n if (timeout) {\n clearTimeout(timeout);\n }\n\n const localPromise = promise = promise || new ZalgoPromise();\n\n timeout = setTimeout(() => {\n promise = null;\n timeout = null;\n\n ZalgoPromise.try(method).then(\n result => { localPromise.resolve(result); },\n err => { localPromise.reject(err); }\n );\n }, delay);\n\n return localPromise;\n };\n\n return setFunctionName(promiseDebounced, `${ getFunctionName(method) }::promiseDebounced`);\n}\n\nexport function safeInterval(method : Function, time : number) : {| cancel : () => void |} {\n\n let timeout;\n\n function loop() {\n timeout = setTimeout(() => {\n method();\n loop();\n }, time);\n }\n\n loop();\n\n return {\n cancel() {\n clearTimeout(timeout);\n }\n };\n}\n\nexport function isInteger(str : string) : boolean {\n return Boolean(str.match(/^[0-9]+$/));\n}\n\nexport function isFloat(str : string) : boolean {\n return Boolean(str.match(/^[0-9]+\\.[0-9]+$/));\n}\n\nexport function serializePrimitive(value : string | number | boolean) : string {\n return value.toString();\n}\n\nexport function deserializePrimitive(value : string) : string | number | boolean {\n if (value === 'true') {\n return true;\n } else if (value === 'false') {\n return false;\n } else if (isInteger(value)) {\n return parseInt(value, 10);\n } else if (isFloat(value)) {\n return parseFloat(value);\n } else {\n return value;\n }\n}\n\nexport function dotify(obj : Object, prefix : string = '', newobj : Object = {}) : { [string] : string } {\n prefix = prefix ? `${ prefix }.` : prefix;\n for (const key in obj) {\n if (!obj.hasOwnProperty(key) || obj[key] === undefined || obj[key] === null || typeof obj[key] === 'function') {\n continue;\n } else if (obj[key] && Array.isArray(obj[key]) && obj[key].length && obj[key].every(val => typeof val !== 'object')) {\n newobj[`${ prefix }${ key }[]`] = obj[key].join(',');\n } else if (obj[key] && typeof obj[key] === 'object') {\n newobj = dotify(obj[key], `${ prefix }${ key }`, newobj);\n } else {\n newobj[`${ prefix }${ key }`] = serializePrimitive(obj[key]);\n }\n }\n return newobj;\n}\n\nexport function undotify(obj : { [string] : string }) : Object {\n \n const result = {};\n\n for (let key in obj) {\n if (!obj.hasOwnProperty(key) || typeof obj[key] !== 'string') {\n continue;\n }\n\n let value = obj[key];\n\n if (key.match(/^.+\\[\\]$/)) {\n key = key.slice(0, -2);\n value = value.split(',').map(deserializePrimitive);\n } else {\n value = deserializePrimitive(value);\n }\n\n let keyResult = result;\n const parts = key.split('.');\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n const isLast = (i + 1 === parts.length);\n const isIndex = !isLast && isInteger(parts[i + 1]);\n\n if (part === 'constructor' || part === 'prototype' || part === '__proto__') {\n throw new Error(`Disallowed key: ${ part }`);\n }\n\n if (isLast) {\n // $FlowFixMe\n keyResult[part] = value;\n } else {\n // $FlowFixMe\n keyResult = keyResult[part] = keyResult[part] || (isIndex ? [] : {});\n }\n }\n }\n\n return result;\n}\n\nexport type EventEmitterType = {|\n on : (eventName : string, handler : Function) => CancelableType,\n once : (eventName : string, handler : Function) => CancelableType,\n trigger : (eventName : string, ...args : $ReadOnlyArray) => ZalgoPromise,\n triggerOnce : (eventName : string, ...args : $ReadOnlyArray) => ZalgoPromise,\n reset : () => void\n|};\n\nexport function eventEmitter() : EventEmitterType {\n const triggered = {};\n let handlers = {};\n\n return {\n\n on(eventName : string, handler : Function) : CancelableType {\n const handlerList = handlers[eventName] = handlers[eventName] || [];\n\n handlerList.push(handler);\n\n let cancelled = false;\n\n return {\n cancel() {\n if (!cancelled) {\n cancelled = true;\n handlerList.splice(handlerList.indexOf(handler), 1);\n }\n\n }\n };\n },\n\n once(eventName : string, handler : Function) : CancelableType {\n\n const listener = this.on(eventName, () => {\n listener.cancel();\n handler();\n });\n\n return listener;\n },\n\n trigger(eventName : string, ...args : $ReadOnlyArray) : ZalgoPromise {\n\n const handlerList = handlers[eventName];\n const promises = [];\n\n if (handlerList) {\n for (const handler of handlerList) {\n promises.push(ZalgoPromise.try(() => handler(...args)));\n }\n }\n\n return ZalgoPromise.all(promises).then(noop);\n },\n\n triggerOnce(eventName : string, ...args : $ReadOnlyArray) : ZalgoPromise {\n\n if (triggered[eventName]) {\n return ZalgoPromise.resolve();\n }\n\n triggered[eventName] = true;\n return this.trigger(eventName, ...args);\n },\n\n reset() {\n handlers = {};\n }\n };\n}\n\nexport function camelToDasherize(string : string) : string {\n return string.replace(/([A-Z])/g, (g) => {\n return `-${ g.toLowerCase() }`;\n });\n}\n\nexport function dasherizeToCamel(string : string) : string {\n return string.replace(/-([a-z])/g, (g) => {\n return g[1].toUpperCase();\n });\n}\n\nexport function capitalizeFirstLetter(string : string) : string {\n return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();\n}\n\nexport function get(item : Object, path : string, def : mixed) : mixed {\n\n if (!path) {\n return def;\n }\n\n const pathParts = path.split('.');\n\n // Loop through each section of our key path\n\n for (let i = 0; i < pathParts.length; i++) {\n\n // If we have an object, we can get the key\n if (typeof item === 'object' && item !== null) {\n item = item[pathParts[i]];\n\n // Otherwise, we should return the default (undefined if not provided)\n } else {\n return def;\n }\n }\n\n // If our final result is undefined, we should return the default\n\n return item === undefined ? def : item;\n}\n\nexport function safeTimeout(method : Function, time : number) {\n\n const interval = safeInterval(() => {\n time -= 100;\n if (time <= 0) {\n interval.cancel();\n method();\n }\n }, 100);\n}\n\nexport function defineLazyProp(obj : Object | $ReadOnlyArray, key : string | number, getter : () => T) {\n if (Array.isArray(obj)) {\n if (typeof key !== 'number') {\n throw new TypeError(`Array key must be number`);\n }\n } else if (typeof obj === 'object' && obj !== null) {\n if (typeof key !== 'string') {\n throw new TypeError(`Object key must be string`);\n }\n }\n \n Object.defineProperty(obj, key, {\n configurable: true,\n enumerable: true,\n get: () => {\n // $FlowFixMe\n delete obj[key];\n const value = getter();\n // $FlowFixMe\n obj[key] = value;\n return value;\n },\n set: (value : T) => {\n // $FlowFixMe\n delete obj[key];\n // $FlowFixMe\n obj[key] = value;\n }\n });\n}\n\nexport function arrayFrom(item : Iterable) : $ReadOnlyArray { // eslint-disable-line no-undef\n return Array.prototype.slice.call(item);\n}\n\nexport function isObject(item : mixed) : boolean {\n return (typeof item === 'object' && item !== null);\n}\n\nexport function isObjectObject(obj : mixed) : boolean {\n return isObject(obj) && Object.prototype.toString.call(obj) === '[object Object]';\n}\n\nexport function isPlainObject(obj : mixed) : boolean {\n if (!isObjectObject(obj)) {\n return false;\n }\n\n // $FlowFixMe\n const constructor = obj.constructor;\n\n if (typeof constructor !== 'function') {\n return false;\n }\n\n const prototype = constructor.prototype;\n\n if (!isObjectObject(prototype)) {\n return false;\n }\n\n if (!prototype.hasOwnProperty('isPrototypeOf')) {\n return false;\n }\n\n return true;\n}\n\nexport function replaceObject | Object> (item : T, replacer : (mixed, string | number, string) => mixed, fullKey : string = '') : T {\n\n if (Array.isArray(item)) {\n const length = item.length;\n const result : Array = [];\n\n for (let i = 0; i < length; i++) {\n\n \n defineLazyProp(result, i, () => {\n const itemKey = fullKey ? `${ fullKey }.${ i }` : `${ i }`;\n const el = item[i];\n\n let child = replacer(el, i, itemKey);\n\n if (isPlainObject(child) || Array.isArray(child)) {\n // $FlowFixMe\n child = replaceObject(child, replacer, itemKey);\n }\n\n return child;\n });\n }\n\n // $FlowFixMe\n return result;\n } else if (isPlainObject(item)) {\n const result = {};\n\n for (const key in item) {\n if (!item.hasOwnProperty(key)) {\n continue;\n }\n\n defineLazyProp(result, key, () => {\n const itemKey = fullKey ? `${ fullKey }.${ key }` : `${ key }`;\n // $FlowFixMe\n const el = item[key];\n\n let child = replacer(el, key, itemKey);\n\n if (isPlainObject(child) || Array.isArray(child)) {\n // $FlowFixMe\n child = replaceObject(child, replacer, itemKey);\n }\n\n return child;\n });\n }\n\n // $FlowFixMe\n return result;\n } else {\n throw new Error(`Pass an object or array`);\n }\n}\n\n\nexport function copyProp(source : Object, target : Object, name : string, def : mixed) {\n if (source.hasOwnProperty(name)) {\n const descriptor = Object.getOwnPropertyDescriptor(source, name);\n // $FlowFixMe\n Object.defineProperty(target, name, descriptor);\n\n } else {\n target[name] = def;\n }\n}\n\ntype RegexResultType = {|\n text : string,\n groups : $ReadOnlyArray,\n start : number,\n end : number,\n length : number,\n replace : (text : string) => string\n|};\n\nexport function regex(pattern : string | RegExp, string : string, start : number = 0) : ?RegexResultType {\n\n if (typeof pattern === 'string') {\n // eslint-disable-next-line security/detect-non-literal-regexp\n pattern = new RegExp(pattern);\n }\n\n const result = string.slice(start).match(pattern);\n\n if (!result) {\n return;\n }\n\n // $FlowFixMe\n const index : number = result.index;\n const regmatch = result[0];\n\n return {\n text: regmatch,\n groups: result.slice(1),\n start: start + index,\n end: start + index + regmatch.length,\n length: regmatch.length,\n\n replace(text : string) : string {\n\n if (!regmatch) {\n return '';\n }\n\n return `${ regmatch.slice(0, start + index) }${ text }${ regmatch.slice(index + regmatch.length) }`;\n }\n };\n}\n\nexport function regexAll(pattern : string | RegExp, string : string) : $ReadOnlyArray {\n\n const matches = [];\n let start = 0;\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const regmatch = regex(pattern, string, start);\n\n if (!regmatch) {\n break;\n }\n\n matches.push(regmatch);\n start = match.end;\n }\n\n return matches;\n}\n\nexport function isDefined(value : ?mixed) : boolean {\n return value !== null && value !== undefined;\n}\n\nexport function cycle(method : Function) : ZalgoPromise {\n return ZalgoPromise.try(method).then(() => cycle(method));\n}\n\nexport function debounce(method : (...args : $ReadOnlyArray) => T, time : number = 100) : (...args : $ReadOnlyArray) => void {\n\n let timeout;\n\n const debounceWrapper = function() {\n clearTimeout(timeout);\n\n timeout = setTimeout(() => {\n return method.apply(this, arguments);\n }, time);\n };\n\n return setFunctionName(debounceWrapper, `${ getFunctionName(method) }::debounced`);\n}\n\nexport function isRegex(item : mixed) : boolean {\n return Object.prototype.toString.call(item) === '[object RegExp]';\n}\n\ntype FunctionProxy = (method : T) => T;\n\n// eslint-disable-next-line flowtype/no-weak-types\nexport const weakMapMemoize : FunctionProxy<*> = (method : (arg : any) => R) : ((...args : $ReadOnlyArray) => R) => {\n\n const weakmap = new WeakMap();\n\n // eslint-disable-next-line flowtype/no-weak-types\n return function weakmapMemoized(arg : any) : R {\n return weakmap.getOrSet(arg, () => method.call(this, arg));\n };\n};\n\ntype FunctionPromiseProxy) => ZalgoPromise> = (T) => T;\n\n// eslint-disable-next-line flowtype/no-weak-types\nexport const weakMapMemoizePromise : FunctionPromiseProxy<*, *> = (method : (arg : any) => ZalgoPromise) : ((...args : $ReadOnlyArray) => ZalgoPromise) => {\n\n const weakmap = new WeakMap();\n\n // eslint-disable-next-line flowtype/no-weak-types\n return function weakmapMemoizedPromise(arg : any) : ZalgoPromise {\n return weakmap.getOrSet(arg, () =>\n method.call(this, arg).finally(() => {\n weakmap.delete(arg);\n }));\n };\n};\n\nexport function getOrSet(obj : O, key : string, getter : () => T) : T {\n if (obj.hasOwnProperty(key)) {\n return obj[key];\n }\n\n const val = getter();\n obj[key] = val;\n return val;\n}\n\nexport type CleanupType = {|\n set : (string, T) => T, // eslint-disable-line no-undef\n register : (Function) => void,\n all : () => ZalgoPromise\n|};\n\nexport function cleanup(obj : Object) : CleanupType {\n\n const tasks = [];\n let cleaned = false;\n\n return {\n set(name : string, item : T) : T {\n if (!cleaned) {\n obj[name] = item;\n this.register(() => {\n delete obj[name];\n });\n }\n return item;\n },\n\n register(method : Function) {\n if (cleaned) {\n method();\n } else {\n tasks.push(once(method));\n }\n },\n\n all() : ZalgoPromise {\n const results = [];\n cleaned = true;\n\n while (tasks.length) {\n const task = tasks.shift();\n results.push(task());\n }\n\n return ZalgoPromise.all(results).then(noop);\n }\n };\n}\n\nexport function tryCatch(fn : () => T) : {| result : T, error : void |} | {| result : void, error : mixed |} {\n let result;\n let error;\n\n try {\n result = fn();\n } catch (err) {\n error = err;\n }\n \n // $FlowFixMe\n return { result, error };\n}\n\n// eslint-disable-next-line flowtype/no-mutable-array\nexport function removeFromArray>(arr : T, item : X) {\n const index = arr.indexOf(item);\n if (index !== -1) {\n arr.splice(index, 1);\n }\n}\n\nexport function assertExists(name : string, thing : void | null | T) : T {\n if (thing === null || typeof thing === 'undefined') {\n throw new Error(`Expected ${ name } to be present`);\n }\n \n return thing;\n}\n\nexport function unique(arr : $ReadOnlyArray) : $ReadOnlyArray {\n const result = {};\n for (const item of arr) {\n result[item] = true;\n }\n return Object.keys(result);\n}\n\nexport const constHas = (constant : T, value : X) : boolean => {\n return memoizedValues(constant).indexOf(value) !== -1;\n};\n\nexport function dedupeErrors(handler : (mixed) => T) : (mixed) => (T | void) {\n const seenErrors = [];\n const seenStringifiedErrors = {};\n\n return (err) => {\n if (seenErrors.indexOf(err) !== -1) {\n return;\n }\n\n seenErrors.push(err);\n\n const stringifiedError = stringifyError(err);\n if (seenStringifiedErrors[stringifiedError]) {\n return;\n }\n\n seenStringifiedErrors[stringifiedError] = true;\n return handler(err);\n };\n}\n\nexport class ExtendableError extends Error {\n constructor(message : string) {\n super(message);\n // eslint-disable-next-line unicorn/custom-error-definition\n this.name = this.constructor.name;\n if (typeof Error.captureStackTrace === 'function') {\n Error.captureStackTrace(this, this.constructor);\n } else {\n this.stack = (new Error(message)).stack;\n }\n }\n}\n \n","/* @flow */\n\nexport function hasNativeWeakMap() : boolean {\n\n if (typeof WeakMap === 'undefined') {\n return false;\n }\n\n if (typeof Object.freeze === 'undefined') {\n return false;\n }\n\n try {\n\n const testWeakMap = new WeakMap();\n const testKey = {};\n const testValue = '__testvalue__';\n\n Object.freeze(testKey);\n\n testWeakMap.set(testKey, testValue);\n\n if (testWeakMap.get(testKey) === testValue) {\n return true;\n }\n\n return false;\n\n } catch (err) {\n\n return false;\n }\n}\n","/* @flow */\n/* eslint max-lines: off */\n\nimport { ZalgoPromise } from 'zalgo-promise/src';\nimport { linkFrameWindow, isWindowClosed,\n type SameDomainWindowType, type CrossDomainWindowType } from 'cross-domain-utils/src';\nimport { WeakMap } from 'cross-domain-safe-weakmap/src';\n\nimport { inlineMemoize, memoize, noop, stringify, capitalizeFirstLetter,\n once, extend, safeInterval, uniqueID, arrayFrom, ExtendableError } from './util';\nimport { isDevice } from './device';\nimport { KEY_CODES, ATTRIBUTES } from './constants';\nimport type { CancelableType } from './types';\n\ntype ElementRefType = string | HTMLElement;\n\nexport function isDocumentReady() : boolean {\n return Boolean(document.body) && (document.readyState === 'complete');\n}\n\nexport function isDocumentInteractive() : boolean {\n return Boolean(document.body) && (document.readyState === 'interactive');\n}\n\nexport function urlEncode(str : string) : string {\n return str.replace(/\\?/g, '%3F').replace(/&/g, '%26').replace(/#/g, '%23').replace(/\\+/g, '%2B');\n}\n\nexport function waitForWindowReady() : ZalgoPromise {\n return inlineMemoize(waitForWindowReady, () : ZalgoPromise => {\n return new ZalgoPromise(resolve => {\n if (isDocumentReady()) {\n resolve();\n }\n\n window.addEventListener('load', () => resolve());\n });\n });\n}\n\ntype WaitForDocumentReady = () => ZalgoPromise;\n\nexport const waitForDocumentReady : WaitForDocumentReady = memoize(() => {\n return new ZalgoPromise(resolve => {\n\n if (isDocumentReady() || isDocumentInteractive()) {\n return resolve();\n }\n\n const interval = setInterval(() => {\n if (isDocumentReady() || isDocumentInteractive()) {\n clearInterval(interval);\n return resolve();\n }\n }, 10);\n });\n});\n\nexport function waitForDocumentBody() : ZalgoPromise {\n return ZalgoPromise.try(() => {\n if (document.body) {\n return document.body;\n }\n\n return waitForDocumentReady().then(() => {\n if (document.body) {\n return document.body;\n }\n\n throw new Error('Document ready but document.body not present');\n });\n });\n}\n\nexport function parseQuery(queryString : string) : Object {\n return inlineMemoize(parseQuery, () : Object => {\n const params = {};\n\n if (!queryString) {\n return params;\n }\n\n if (queryString.indexOf('=') === -1) {\n return params;\n }\n\n for (let pair of queryString.split('&')) {\n pair = pair.split('=');\n\n if (pair[0] && pair[1]) {\n params[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);\n }\n }\n\n return params;\n }, [ queryString ]);\n}\n\n\nexport function getQueryParam(name : string) : string {\n return parseQuery(window.location.search.slice(1))[name];\n}\n\nexport function urlWillRedirectPage(url : string) : boolean {\n\n if (url.indexOf('#') === -1) {\n return true;\n }\n\n if (url.indexOf('#') === 0) {\n return false;\n }\n\n if (url.split('#')[0] === window.location.href.split('#')[0]) {\n return false;\n }\n\n return true;\n}\n\nexport function formatQuery(obj : { [ string ] : string } = {}) : string {\n\n return Object.keys(obj).filter(key => {\n return typeof obj[key] === 'string';\n }).map(key => {\n return `${ urlEncode(key) }=${ urlEncode(obj[key]) }`;\n }).join('&');\n}\n\nexport function extendQuery(originalQuery : string, props : { [ string ] : string } = {}) : string {\n\n if (!props || !Object.keys(props).length) {\n return originalQuery;\n }\n\n return formatQuery({\n ...parseQuery(originalQuery),\n ...props\n });\n}\n\nexport function extendUrl(url : string, options : {| query? : { [string] : string }, hash? : { [string] : string } |}) : string {\n\n const query = options.query || {};\n const hash = options.hash || {};\n\n let originalUrl;\n let originalQuery;\n let originalHash;\n\n [ originalUrl, originalHash ] = url.split('#');\n [ originalUrl, originalQuery ] = originalUrl.split('?');\n\n const queryString = extendQuery(originalQuery, query);\n const hashString = extendQuery(originalHash, hash);\n\n if (queryString) {\n originalUrl = `${ originalUrl }?${ queryString }`;\n }\n\n if (hashString) {\n originalUrl = `${ originalUrl }#${ hashString }`;\n }\n\n return originalUrl;\n}\n\nexport function redirect(url : string, win : CrossDomainWindowType = window) : ZalgoPromise {\n return new ZalgoPromise(resolve => {\n win.location = url;\n if (!urlWillRedirectPage(url)) {\n resolve();\n }\n });\n}\n\nexport function hasMetaViewPort() : boolean {\n const meta = document.querySelector('meta[name=viewport]');\n\n if (isDevice() && window.screen.width < 660 && !meta) {\n return false;\n }\n\n return true;\n}\n\nexport function isElementVisible(el : HTMLElement) : boolean {\n return Boolean(el.offsetWidth || el.offsetHeight || el.getClientRects().length);\n}\n\nexport function getPerformance() : ?Performance {\n return inlineMemoize(getPerformance, () : ?Performance => {\n const performance = window.performance;\n\n if (\n performance &&\n performance.now &&\n performance.timing &&\n performance.timing.connectEnd &&\n performance.timing.navigationStart &&\n (Math.abs(performance.now() - Date.now()) > 1000) &&\n (performance.now() - (performance.timing.connectEnd - performance.timing.navigationStart)) > 0\n ) {\n return performance;\n }\n });\n}\n\nexport function enablePerformance() : boolean {\n return Boolean(getPerformance());\n}\n\nexport function getPageRenderTime() : ZalgoPromise {\n return waitForDocumentReady().then(() => {\n const performance = getPerformance();\n\n if (!performance) {\n return;\n }\n \n const timing = performance.timing;\n\n if (timing.connectEnd && timing.domInteractive) {\n return timing.domInteractive - timing.connectEnd;\n }\n });\n}\n\nexport function htmlEncode(html : string = '') : string {\n return html.toString()\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n .replace(/\\//g, '/');\n}\n\nexport function isBrowser() : boolean {\n return (typeof window !== 'undefined');\n}\n\nexport function querySelectorAll(selector : string, doc : HTMLElement = window.document) : $ReadOnlyArray {\n return Array.prototype.slice.call(doc.querySelectorAll(selector));\n}\n\nexport function onClick(element : HTMLElement, handler : (Event) => void) {\n element.addEventListener('touchstart', noop);\n element.addEventListener('click', handler);\n element.addEventListener('keypress', (event : Event) => {\n // $FlowFixMe\n if (event.keyCode === KEY_CODES.ENTER || event.keyCode === KEY_CODES.SPACE) { // eslint-disable-line unicorn/prefer-event-key\n return handler(event);\n }\n });\n}\n\nexport function getScript({ host = window.location.host, path, reverse = false } : {| host? : string, path : string, reverse? : boolean |}) : ?HTMLScriptElement {\n return inlineMemoize(getScript, () : ?HTMLScriptElement => {\n\n const url = `${ host }${ path }`;\n const scripts = Array.prototype.slice.call(document.getElementsByTagName('script'));\n\n if (reverse) {\n scripts.reverse();\n }\n\n for (const script of scripts) {\n if (!script.src) {\n continue;\n }\n\n const src = script.src.replace(/^https?:\\/\\//, '').split('?')[0];\n\n if (src === url) {\n return script;\n }\n }\n }, [ path ]);\n}\n\nexport function isLocalStorageEnabled() : boolean {\n return inlineMemoize(isLocalStorageEnabled, () => {\n try {\n if (typeof window === 'undefined') {\n return false;\n }\n\n if (window.localStorage) {\n const value = Math.random().toString();\n window.localStorage.setItem('__test__localStorage__', value);\n const result = window.localStorage.getItem('__test__localStorage__');\n window.localStorage.removeItem('__test__localStorage__');\n if (value === result) {\n return true;\n }\n }\n } catch (err) {\n // pass\n }\n return false;\n });\n}\n\nexport function getBrowserLocales() : $ReadOnlyArray<{| country? : string, lang : string |}> {\n const nav = window.navigator; // eslint-disable-line compat/compat\n\n const locales = nav.languages\n ? [ ...nav.languages ]\n : [];\n\n if (nav.language) {\n locales.push(nav.language);\n }\n\n if (nav.userLanguage) {\n locales.push(nav.userLanguage);\n }\n\n return locales.map(locale => {\n\n if (locale && locale.match(/^[a-z]{2}[-_][A-Z]{2}$/)) {\n const [ lang, country ] = locale.split(/[-_]/);\n return { country, lang };\n }\n\n if (locale && locale.match(/^[a-z]{2}$/)) {\n return { lang: locale };\n }\n\n return null;\n\n }).filter(Boolean);\n}\n\n\nexport function appendChild(container : HTMLElement, child : HTMLElement | Text) {\n container.appendChild(child);\n}\n\nexport function isElement(element : mixed) : boolean {\n\n if (element instanceof window.Element) {\n return true;\n }\n\n if (element !== null && typeof element === 'object' && element.nodeType === 1 && typeof element.style === 'object' && typeof element.ownerDocument === 'object') {\n return true;\n }\n\n return false;\n}\n\nexport function getElementSafe(id : ElementRefType, doc : Document | HTMLElement = document) : ?HTMLElement {\n\n if (isElement(id)) {\n // $FlowFixMe\n return id;\n }\n\n if (typeof id === 'string') {\n return doc.querySelector(id);\n }\n}\n\nexport function getElement(id : ElementRefType, doc : Document | HTMLElement = document) : HTMLElement {\n\n const element = getElementSafe(id, doc);\n\n if (element) {\n return element;\n }\n\n throw new Error(`Can not find element: ${ stringify(id) }`);\n}\n\nexport function elementReady(id : ElementRefType) : ZalgoPromise {\n return new ZalgoPromise((resolve, reject) => {\n\n const name = stringify(id);\n let el = getElementSafe(id);\n\n if (el) {\n return resolve(el);\n }\n\n if (isDocumentReady()) {\n return reject(new Error(`Document is ready and element ${ name } does not exist`));\n }\n\n const interval = setInterval(() => {\n\n el = getElementSafe(id);\n\n if (el) {\n clearInterval(interval);\n return resolve(el);\n }\n\n if (isDocumentReady()) {\n clearInterval(interval);\n return reject(new Error(`Document is ready and element ${ name } does not exist`));\n }\n }, 10);\n });\n}\n\n// eslint-disable-next-line unicorn/custom-error-definition\nexport class PopupOpenError extends ExtendableError {}\n\ntype PopupOptions = {|\n name? : string,\n width? : number,\n height? : number,\n top? : number,\n left? : number,\n status? : 0 | 1,\n resizable? : 0 | 1,\n toolbar? : 0 | 1,\n menubar? : 0 | 1,\n scrollbars? : 0 | 1\n|};\n\nexport function popup(url : string, options? : PopupOptions) : CrossDomainWindowType {\n\n // $FlowFixMe\n options = options || {};\n\n const { width, height } = options;\n\n let top = 0;\n let left = 0;\n\n if (width) {\n if (window.outerWidth) {\n left = Math.round((window.outerWidth - width) / 2) + window.screenX;\n } else if (window.screen.width) {\n left = Math.round((window.screen.width - width) / 2);\n }\n }\n\n if (height) {\n if (window.outerHeight) {\n top = Math.round((window.outerHeight - height) / 2) + window.screenY;\n } else if (window.screen.height) {\n top = Math.round((window.screen.height - height) / 2);\n }\n }\n\n if (width && height) {\n // $FlowFixMe\n options = {\n top,\n left,\n width,\n height,\n status: 1,\n toolbar: 0,\n menubar: 0,\n resizable: 1,\n scrollbars: 1,\n ...options\n };\n }\n\n const name = options.name || '';\n delete options.name;\n\n // eslint-disable-next-line array-callback-return\n const params = Object.keys(options).map(key => {\n // $FlowFixMe\n if (options[key] !== null && options[key] !== undefined) {\n return `${ key }=${ stringify(options[key]) }`;\n }\n }).filter(Boolean).join(',');\n\n let win;\n\n try {\n win = window.open(url, name, params, true);\n } catch (err) {\n throw new PopupOpenError(`Can not open popup window - ${ err.stack || err.message }`);\n }\n\n if (isWindowClosed(win)) {\n const err = new PopupOpenError(`Can not open popup window - blocked`);\n throw err;\n }\n\n window.addEventListener('unload', () => win.close());\n\n return win;\n}\n\n\nexport function writeToWindow(win : SameDomainWindowType, html : string) {\n try {\n win.document.open();\n win.document.write(html);\n win.document.close();\n } catch (err) {\n try {\n win.location = `javascript: document.open(); document.write(${ JSON.stringify(html) }); document.close();`;\n } catch (err2) {\n // pass\n }\n }\n}\n\nexport function writeElementToWindow(win : SameDomainWindowType, el : HTMLElement) {\n\n const tag = el.tagName.toLowerCase();\n\n if (tag !== 'html') {\n throw new Error(`Expected element to be html, got ${ tag }`);\n }\n\n const documentElement = win.document.documentElement;\n\n for (const child of arrayFrom(documentElement.children)) {\n documentElement.removeChild(child);\n }\n\n for (const child of arrayFrom(el.children)) {\n documentElement.appendChild(child);\n }\n}\n\nexport function setStyle(el : HTMLElement, styleText : string, doc : Document = window.document) {\n // $FlowFixMe\n if (el.styleSheet) {\n // $FlowFixMe\n el.styleSheet.cssText = styleText;\n } else {\n el.appendChild(doc.createTextNode(styleText));\n }\n}\n\nexport type ElementOptionsType = {|\n style? : { [ string ] : string },\n id? : string,\n class? : ?$ReadOnlyArray,\n attributes? : { [ string ] : string },\n styleSheet? : ?string,\n html? : ?string\n|};\n\nlet awaitFrameLoadPromises : WeakMap>;\n\nexport function awaitFrameLoad(frame : HTMLIFrameElement) : ZalgoPromise {\n awaitFrameLoadPromises = awaitFrameLoadPromises || new WeakMap();\n\n if (awaitFrameLoadPromises.has(frame)) {\n const promise = awaitFrameLoadPromises.get(frame);\n if (promise) {\n return promise;\n }\n }\n\n const promise = new ZalgoPromise((resolve, reject) => {\n frame.addEventListener('load', () => {\n linkFrameWindow(frame);\n resolve(frame);\n });\n\n frame.addEventListener('error', (err : Event) => {\n if (frame.contentWindow) {\n resolve(frame);\n } else {\n reject(err);\n }\n });\n });\n\n awaitFrameLoadPromises.set(frame, promise);\n\n return promise;\n}\n\nexport function awaitFrameWindow(frame : HTMLIFrameElement) : ZalgoPromise {\n return awaitFrameLoad(frame).then(loadedFrame => {\n\n if (!loadedFrame.contentWindow) {\n throw new Error(`Could not find window in iframe`);\n }\n\n return loadedFrame.contentWindow;\n });\n}\n\nconst getDefaultCreateElementOptions = () : ElementOptionsType => {\n // $FlowFixMe\n return {};\n};\n\nexport function createElement(tag : string = 'div', options : ElementOptionsType = getDefaultCreateElementOptions(), container : ?HTMLElement) : HTMLElement {\n\n tag = tag.toLowerCase();\n const element = document.createElement(tag);\n\n if (options.style) {\n extend(element.style, options.style);\n }\n\n if (options.class) {\n element.className = options.class.join(' ');\n }\n\n if (options.id) {\n element.setAttribute('id', options.id);\n }\n\n if (options.attributes) {\n for (const key of Object.keys(options.attributes)) {\n element.setAttribute(key, options.attributes[key]);\n }\n }\n\n if (options.styleSheet) {\n setStyle(element, options.styleSheet);\n }\n\n if (container) {\n appendChild(container, element);\n }\n\n if (options.html) {\n if (tag === 'iframe') {\n // $FlowFixMe\n if (!container || !element.contentWindow) {\n throw new Error(`Iframe html can not be written unless container provided and iframe in DOM`);\n }\n\n // $FlowFixMe\n writeToWindow(element.contentWindow, options.html);\n\n } else {\n element.innerHTML = options.html;\n }\n }\n\n return element;\n}\n\ntype StringMap = {|\n [ string ] : string\n|};\n\nexport type IframeElementOptionsType = {|\n style? : StringMap,\n class? : ?$ReadOnlyArray,\n attributes? : StringMap,\n styleSheet? : ?string,\n html? : ?string,\n url? : ?string\n|};\n\nconst getDefaultIframeOptions = () : IframeElementOptionsType => {\n // $FlowFixMe\n return {};\n};\n\nconst getDefaultStringMap = () : StringMap => {\n // $FlowFixMe\n return {};\n};\n\nexport function iframe(options : IframeElementOptionsType = getDefaultIframeOptions(), container : ?HTMLElement) : HTMLIFrameElement {\n\n const attributes = options.attributes || getDefaultStringMap();\n const style = options.style || getDefaultStringMap();\n\n // $FlowFixMe\n const newAttributes = {\n allowTransparency: 'true',\n ...attributes\n };\n\n // $FlowFixMe\n const newStyle = {\n backgroundColor: 'transparent',\n border: 'none',\n ...style\n };\n\n const frame = createElement('iframe', {\n attributes: newAttributes,\n style: newStyle,\n html: options.html,\n class: options.class\n });\n\n const isIE = window.navigator.userAgent.match(/MSIE|Edge/i); // eslint-disable-line compat/compat\n\n if (!frame.hasAttribute('id')) {\n frame.setAttribute('id', uniqueID());\n }\n\n // $FlowFixMe\n awaitFrameLoad(frame);\n\n if (container) {\n const el = getElement(container);\n el.appendChild(frame);\n }\n\n if (options.url || isIE) {\n frame.setAttribute('src', options.url || 'about:blank');\n }\n\n // $FlowFixMe\n return frame;\n}\n\nexport function addEventListener(obj : HTMLElement, event : string, handler : (event : Event) => void) : CancelableType {\n obj.addEventListener(event, handler);\n return {\n cancel() {\n obj.removeEventListener(event, handler);\n }\n };\n}\n\nexport function bindEvents(element : HTMLElement, eventNames : $ReadOnlyArray, handler : (event : Event) => void) : CancelableType {\n\n handler = once(handler);\n\n for (const eventName of eventNames) {\n element.addEventListener(eventName, handler);\n }\n\n return {\n cancel: once(() => {\n for (const eventName of eventNames) {\n element.removeEventListener(eventName, handler);\n }\n })\n };\n}\n\nconst VENDOR_PREFIXES = [ 'webkit', 'moz', 'ms', 'o' ];\n\nexport function setVendorCSS(element : HTMLElement, name : string, value : string) {\n\n // $FlowFixMe\n element.style[name] = value;\n\n const capitalizedName = capitalizeFirstLetter(name);\n\n for (const prefix of VENDOR_PREFIXES) {\n // $FlowFixMe\n element.style[`${ prefix }${ capitalizedName }`] = value;\n }\n}\n\nconst ANIMATION_START_EVENTS = [ 'animationstart', 'webkitAnimationStart', 'oAnimationStart', 'MSAnimationStart' ];\nconst ANIMATION_END_EVENTS = [ 'animationend', 'webkitAnimationEnd', 'oAnimationEnd', 'MSAnimationEnd' ];\n\nexport function animate(element : ElementRefType, name : string, clean : (Function) => void, timeout : number = 1000) : ZalgoPromise {\n return new ZalgoPromise((resolve, reject) => {\n\n const el = getElement(element);\n\n if (!el) {\n return resolve();\n }\n\n let hasStarted = false;\n\n // eslint-disable-next-line prefer-const\n let startTimeout;\n let endTimeout;\n // eslint-disable-next-line prefer-const\n let startEvent;\n // eslint-disable-next-line prefer-const\n let endEvent;\n\n function cleanUp() {\n clearTimeout(startTimeout);\n clearTimeout(endTimeout);\n startEvent.cancel();\n endEvent.cancel();\n }\n\n startEvent = bindEvents(el, ANIMATION_START_EVENTS, event => {\n\n // $FlowFixMe\n if (event.target !== el || event.animationName !== name) {\n return;\n }\n\n clearTimeout(startTimeout);\n\n event.stopPropagation();\n\n startEvent.cancel();\n hasStarted = true;\n\n endTimeout = setTimeout(() => {\n cleanUp();\n resolve();\n }, timeout);\n });\n\n endEvent = bindEvents(el, ANIMATION_END_EVENTS, event => {\n\n // $FlowFixMe\n if (event.target !== el || event.animationName !== name) {\n return;\n }\n\n cleanUp();\n\n // $FlowFixMe\n if (typeof event.animationName === 'string' && event.animationName !== name) {\n return reject(`Expected animation name to be ${ name }, found ${ event.animationName }`);\n }\n\n return resolve();\n });\n\n setVendorCSS(el, 'animationName', name);\n\n startTimeout = setTimeout(() => {\n if (!hasStarted) {\n cleanUp();\n return resolve();\n }\n }, 200);\n\n if (clean) {\n clean(cleanUp);\n }\n });\n}\n\nexport function makeElementVisible(element : HTMLElement) {\n element.style.setProperty('visibility', '');\n}\n\nexport function makeElementInvisible(element : HTMLElement) {\n element.style.setProperty('visibility', 'hidden', 'important');\n}\n\n\nexport function showElement(element : HTMLElement) {\n element.style.setProperty('display', '');\n}\n\nexport function hideElement(element : HTMLElement) {\n element.style.setProperty('display', 'none', 'important');\n}\n\nexport function destroyElement(element : HTMLElement) {\n if (element && element.parentNode) {\n element.parentNode.removeChild(element);\n }\n}\n\nexport function showAndAnimate(element : HTMLElement, name : string, clean : (Function) => void) : ZalgoPromise {\n const animation = animate(element, name, clean);\n showElement(element);\n return animation;\n}\n\nexport function animateAndHide(element : HTMLElement, name : string, clean : (Function) => void) : ZalgoPromise {\n return animate(element, name, clean).then(() => {\n hideElement(element);\n });\n}\n\nexport function addClass(element : HTMLElement, name : string) {\n element.classList.add(name);\n}\n\nexport function removeClass(element : HTMLElement, name : string) {\n element.classList.remove(name);\n}\n\nexport function isElementClosed(el : HTMLElement) : boolean {\n if (!el || !el.parentNode) {\n return true;\n }\n return false;\n}\n\nexport function watchElementForClose(element : HTMLElement, handler : () => mixed) : CancelableType {\n handler = once(handler);\n\n let interval;\n\n if (isElementClosed(element)) {\n handler();\n } else {\n interval = safeInterval(() => {\n if (isElementClosed(element)) {\n interval.cancel();\n handler();\n }\n }, 50);\n }\n\n return {\n cancel() {\n if (interval) {\n interval.cancel();\n }\n }\n };\n}\n\nexport function fixScripts(el : HTMLElement, doc : Document = window.document) {\n for (const script of querySelectorAll('script', el)) {\n const parentNode = script.parentNode;\n\n if (!parentNode) {\n continue;\n }\n\n const newScript = doc.createElement('script');\n newScript.text = script.textContent;\n parentNode.replaceChild(newScript, script);\n }\n}\n\ntype OnResizeOptions = {|\n width? : boolean,\n height? : boolean,\n interval? : number,\n win? : SameDomainWindowType\n|};\n\nexport function onResize(el : HTMLElement, handler : ({| width : number, height : number |}) => void, { width = true, height = true, interval = 100, win = window } : OnResizeOptions = {}) : {| cancel : () => void |} {\n let currentWidth = el.offsetWidth;\n let currentHeight = el.offsetHeight;\n let canceled = false;\n\n handler({ width: currentWidth, height: currentHeight });\n\n const check = () => {\n if (canceled || !isElementVisible(el)) {\n return;\n }\n\n const newWidth = el.offsetWidth;\n const newHeight = el.offsetHeight;\n\n if ((width && newWidth !== currentWidth) || (height && newHeight !== currentHeight)) {\n handler({ width: newWidth, height: newHeight });\n }\n\n currentWidth = newWidth;\n currentHeight = newHeight;\n };\n\n let observer;\n let timeout;\n\n win.addEventListener('resize', check);\n \n if (typeof win.ResizeObserver !== 'undefined') {\n observer = new win.ResizeObserver(check);\n observer.observe(el);\n timeout = safeInterval(check, interval * 10);\n\n } else if (typeof win.MutationObserver !== 'undefined') {\n observer = new win.MutationObserver(check);\n observer.observe(el, {\n attributes: true,\n childList: true,\n subtree: true,\n characterData: false\n });\n timeout = safeInterval(check, interval * 10);\n } else {\n timeout = safeInterval(check, interval);\n }\n\n return {\n cancel: () => {\n canceled = true;\n observer.disconnect();\n window.removeEventListener('resize', check);\n timeout.cancel();\n }\n };\n}\n\nexport function getResourceLoadTime(url : string) : ?number {\n const performance = getPerformance();\n\n if (!performance) {\n return;\n }\n\n if (typeof performance.getEntries !== 'function') {\n return;\n }\n\n const entries = performance.getEntries();\n\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n\n if (entry && entry.name && entry.name.indexOf(url) === 0 && typeof entry.duration === 'number') {\n return Math.floor(entry.duration);\n }\n }\n}\n\nexport function isShadowElement(element : Node) : boolean {\n while (element.parentNode) {\n element = element.parentNode;\n }\n\n return element.toString() === '[object ShadowRoot]';\n}\n\nexport function getShadowRoot(element : Node) : ?Node {\n while (element.parentNode) {\n element = element.parentNode;\n }\n\n if (isShadowElement(element)) {\n return element;\n }\n}\n\nexport function getShadowHost(element : Node) : ?HTMLElement {\n const shadowRoot = getShadowRoot(element);\n\n // $FlowFixMe\n if (shadowRoot.host) {\n // $FlowFixMe\n return shadowRoot.host;\n }\n}\n\nexport function insertShadowSlot(element : HTMLElement) : HTMLElement {\n const shadowHost = getShadowHost(element);\n\n if (!shadowHost) {\n throw new Error(`Element is not in shadow dom`);\n }\n\n if (isShadowElement(shadowHost)) {\n throw new Error(`Host element is also in shadow dom`);\n }\n\n const slotName = `shadow-slot-${ uniqueID() }`;\n\n const slot = document.createElement('slot');\n slot.setAttribute('name', slotName);\n element.appendChild(slot);\n \n const slotProvider = document.createElement('div');\n slotProvider.setAttribute('slot', slotName);\n shadowHost.appendChild(slotProvider);\n\n return slotProvider;\n}\n\nexport function preventClickFocus(el : HTMLElement) {\n const onFocus = (event : Event) => {\n el.removeEventListener('focus', onFocus);\n event.preventDefault();\n el.blur();\n return false;\n };\n\n el.addEventListener('mousedown', () => {\n el.addEventListener('focus', onFocus);\n setTimeout(() => {\n el.removeEventListener('focus', onFocus);\n }, 1);\n });\n}\n\nexport function getStackTrace() : string {\n try {\n throw new Error('_');\n }\n catch (err) {\n return err.stack || '';\n }\n}\n\nfunction inferCurrentScript() : ?HTMLScriptElement {\n try {\n const stack = getStackTrace();\n const stackDetails = (/.*at [^(]*\\((.*):(.+):(.+)\\)$/ig).exec(stack);\n const scriptLocation = stackDetails && stackDetails[1];\n\n if (!scriptLocation) {\n return;\n }\n\n for (const script of Array.prototype.slice.call(document.getElementsByTagName('script')).reverse()) {\n if (script.src && script.src === scriptLocation) {\n return script;\n }\n }\n\n } catch (err) {\n // pass\n }\n}\n\n// eslint-disable-next-line compat/compat\nlet currentScript = typeof document !== 'undefined' ? document.currentScript : null;\n\ntype GetCurrentScript = () => HTMLScriptElement;\n\nexport const getCurrentScript : GetCurrentScript = memoize(() => {\n if (currentScript) {\n return currentScript;\n }\n\n currentScript = inferCurrentScript();\n\n if (currentScript) {\n return currentScript;\n }\n\n throw new Error('Can not determine current script');\n});\n\nconst currentUID = uniqueID();\n\ntype GetCurrentScriptUID = () => string;\n\nexport const getCurrentScriptUID : GetCurrentScriptUID = memoize(() => {\n let script;\n\n try {\n script = getCurrentScript();\n } catch (err) {\n return currentUID;\n }\n\n let uid = script.getAttribute(ATTRIBUTES.UID);\n\n if (uid && typeof uid === 'string') {\n return uid;\n }\n\n uid = uniqueID();\n script.setAttribute(ATTRIBUTES.UID, uid);\n\n return uid;\n});\n","/* @flow */\n\nexport const KEY_CODES = {\n ENTER: 13,\n SPACE: 32\n};\n\nexport const ATTRIBUTES = {\n UID: 'data-uid'\n};\n","/* @flow */\n\nimport { ZalgoPromise } from 'zalgo-promise/src';\nimport { type SameDomainWindowType } from 'cross-domain-utils/src';\n\ntype RequestOptionsType = {|\n url : string,\n method? : string,\n headers? : { [key : string] : string },\n json? : $ReadOnlyArray | Object,\n data? : { [key : string] : string },\n body? : string,\n win? : SameDomainWindowType,\n timeout? : number\n|};\n\ntype ResponseType = {|\n status : number,\n headers : { [string] : string },\n body : Object\n|};\n\nconst HEADERS = {\n CONTENT_TYPE: 'content-type',\n ACCEPT: 'accept'\n};\n\nconst headerBuilders = [];\n\nfunction parseHeaders(rawHeaders : string = '') : { [string] : string } {\n const result = {};\n for (const line of rawHeaders.trim().split('\\n')) {\n const [ key, ...values ] = line.split(':');\n result[key.toLowerCase()] = values.join(':').trim();\n }\n return result;\n}\n\nexport function request({ url, method = 'get', headers = {}, json, data, body, win = window, timeout = 0 } : RequestOptionsType) : ZalgoPromise {\n return new ZalgoPromise((resolve, reject) => {\n\n if ((json && data) || (json && body) || (data && json)) {\n throw new Error(`Only options.json or options.data or options.body should be passed`);\n }\n\n const normalizedHeaders = {};\n\n for (const key of Object.keys(headers)) {\n normalizedHeaders[key.toLowerCase()] = headers[key];\n }\n\n if (json) {\n normalizedHeaders[HEADERS.CONTENT_TYPE] = normalizedHeaders[HEADERS.CONTENT_TYPE] || 'application/json';\n } else if (data || body) {\n normalizedHeaders[HEADERS.CONTENT_TYPE] = normalizedHeaders[HEADERS.CONTENT_TYPE] || 'application/x-www-form-urlencoded; charset=utf-8';\n }\n\n normalizedHeaders[HEADERS.ACCEPT] = normalizedHeaders[HEADERS.ACCEPT] || 'application/json';\n\n for (const headerBuilder of headerBuilders) {\n const builtHeaders = headerBuilder();\n\n for (const key of Object.keys(builtHeaders)) {\n normalizedHeaders[key.toLowerCase()] = builtHeaders[key];\n }\n }\n\n const xhr = new win.XMLHttpRequest();\n\n xhr.addEventListener('load', function xhrLoad() : void {\n\n const responseHeaders = parseHeaders(this.getAllResponseHeaders());\n\n if (!this.status) {\n return reject(new Error(`Request to ${ method.toLowerCase() } ${ url } failed: no response status code.`));\n }\n \n const contentType = responseHeaders['content-type'];\n const isJSON = contentType && (contentType.indexOf('application/json') === 0 || contentType.indexOf('text/json') === 0);\n let responseBody = this.responseText;\n\n try {\n responseBody = JSON.parse(responseBody);\n } catch (err) {\n if (isJSON) {\n return reject(new Error(`Invalid json: ${ this.responseText }.`));\n }\n }\n\n const res = {\n status: this.status,\n headers: responseHeaders,\n body: responseBody\n };\n\n return resolve(res);\n\n }, false);\n\n xhr.addEventListener('error', (evt) => {\n reject(new Error(`Request to ${ method.toLowerCase() } ${ url } failed: ${ evt.toString() }.`));\n }, false);\n\n xhr.open(method, url, true);\n\n for (const key in normalizedHeaders) {\n if (normalizedHeaders.hasOwnProperty(key)) {\n xhr.setRequestHeader(key, normalizedHeaders[key]);\n }\n }\n\n if (json) {\n body = JSON.stringify(json);\n } else if (data) {\n body = Object.keys(data).map(key => {\n return `${ encodeURIComponent(key) }=${ data ? encodeURIComponent(data[key]) : '' }`;\n }).join('&');\n }\n\n xhr.timeout = timeout;\n xhr.ontimeout = function xhrTimeout() {\n reject(new Error(`Request to ${ method.toLowerCase() } ${ url } has timed out`));\n };\n\n xhr.send(body);\n });\n}\n\nexport function addHeaderBuilder(method : () => { [string] : string }) {\n headerBuilders.push(method);\n}\n","/* @flow */\n\nexport const LOG_LEVEL = {\n DEBUG: ('debug' : 'debug'),\n INFO: ('info' : 'info'),\n WARN: ('warn' : 'warn'),\n ERROR: ('error' : 'error')\n};\n\nexport const PROTOCOL = {\n FILE: 'file:'\n};\n","/* @flow */\n\nimport { LOG_LEVEL } from './constants';\n\nexport const AUTO_FLUSH_LEVEL = [ LOG_LEVEL.WARN, LOG_LEVEL.ERROR ];\n\nexport const LOG_LEVEL_PRIORITY = [ LOG_LEVEL.ERROR, LOG_LEVEL.WARN, LOG_LEVEL.INFO, LOG_LEVEL.DEBUG ];\n\nexport const FLUSH_INTERVAL = 60 * 1000;\n\nexport const DEFAULT_LOG_LEVEL : $Values = __DEBUG__ ? LOG_LEVEL.DEBUG : LOG_LEVEL.WARN;\n","/* @flow */\n\nimport { ZalgoPromise } from 'zalgo-promise/src';\nimport { request, isBrowser, promiseDebounce, noop, safeInterval, objFilter } from 'belter/src';\n\nimport { DEFAULT_LOG_LEVEL, LOG_LEVEL_PRIORITY, AUTO_FLUSH_LEVEL, FLUSH_INTERVAL } from './config';\nimport { LOG_LEVEL, PROTOCOL } from './constants';\n\ntype TransportOptions = {|\n url : string,\n method : string,\n headers : { [string] : string },\n json : Object,\n enableSendBeacon : boolean\n|};\n\ntype Payload = { [string] : string | boolean };\ntype Transport = (TransportOptions) => ZalgoPromise;\n\ntype LoggerOptions = {|\n url : string,\n prefix? : string,\n logLevel? : $Values,\n transport? : Transport,\n flushInterval? : number,\n enableSendBeacon? : boolean,\n enableBrowserLogging? : boolean\n|};\n\ntype ClientPayload = { [string] : ?string | ?boolean };\ntype Log = (name : string, payload? : ClientPayload) => LoggerType; // eslint-disable-line no-use-before-define\ntype Track = (payload : ClientPayload) => LoggerType; // eslint-disable-line no-use-before-define\n\ntype Builder = (Payload) => ClientPayload;\ntype AddBuilder = (Builder) => LoggerType; // eslint-disable-line no-use-before-define\n\nexport type LoggerType = {|\n debug : Log,\n info : Log,\n warn : Log,\n error : Log,\n\n track : Track,\n\n flush : () => ZalgoPromise,\n immediateFlush : () => ZalgoPromise,\n\n addPayloadBuilder : AddBuilder,\n addMetaBuilder : AddBuilder,\n addTrackingBuilder : AddBuilder,\n addHeaderBuilder : AddBuilder,\n\n setTransport : (Transport) => LoggerType\n|};\n\nfunction httpTransport({ url, method, headers, json, enableSendBeacon = false } : TransportOptions) : ZalgoPromise {\n const hasHeaders = headers && Object.keys(headers).length;\n if (window && window.navigator.sendBeacon && !hasHeaders && enableSendBeacon && window.Blob) {\n return new ZalgoPromise(resolve => {\n const blob = new Blob([ JSON.stringify(json) ], { type: 'application/json' });\n resolve(window.navigator.sendBeacon(url, blob));\n });\n } else {\n return request({ url, method, headers, json }).then(noop);\n }\n}\n\nfunction extendIfDefined(target : { [string] : string | boolean }, source : { [string] : ?string | ?boolean }) {\n for (const key in source) {\n if (source.hasOwnProperty(key) && source[key] && !target[key]) {\n target[key] = source[key];\n }\n }\n}\n\nexport function Logger({ url, prefix, logLevel = DEFAULT_LOG_LEVEL, transport = httpTransport, flushInterval = FLUSH_INTERVAL, enableSendBeacon = false, enableBrowserLogging = true } : LoggerOptions) : LoggerType {\n\n let events : Array<{| level : $Values, event : string, payload : Payload |}> = [];\n let tracking : Array = [];\n\n const payloadBuilders : Array = [];\n const metaBuilders : Array = [];\n const trackingBuilders : Array = [];\n const headerBuilders : Array = [];\n\n function print(level : $Values, event : string, payload : Payload) {\n\n if (!isBrowser() || !window.console || !window.console.log || !enableBrowserLogging) {\n return;\n }\n\n if (LOG_LEVEL_PRIORITY.indexOf(level) > LOG_LEVEL_PRIORITY.indexOf(logLevel)) {\n return;\n }\n\n const args = [ event ];\n\n args.push(payload);\n\n if (payload.error || payload.warning) {\n args.push('\\n\\n', payload.error || payload.warning);\n }\n\n try {\n if (window.console[level] && window.console[level].apply) {\n window.console[level].apply(window.console, args);\n } else if (window.console.log && window.console.log.apply) {\n window.console.log.apply(window.console, args);\n }\n } catch (err) {\n // pass\n }\n }\n\n function immediateFlush() : ZalgoPromise {\n return ZalgoPromise.try(() => {\n if (!isBrowser() || window.location.protocol === PROTOCOL.FILE) {\n return;\n }\n\n if (!events.length && !tracking.length) {\n return;\n }\n\n const meta = {};\n for (const builder of metaBuilders) {\n extendIfDefined(meta, builder(meta));\n }\n\n const headers = {};\n for (const builder of headerBuilders) {\n extendIfDefined(headers, builder(headers));\n }\n\n const res = transport({\n method: 'POST',\n url,\n headers,\n json: {\n events,\n meta,\n tracking\n },\n enableSendBeacon\n });\n\n events = [];\n tracking = [];\n\n return res.then(noop);\n });\n }\n\n const flush = promiseDebounce(immediateFlush);\n\n function enqueue(level : $Values, event : string, payload : Payload) {\n\n events.push({\n level,\n event,\n payload\n });\n\n if (AUTO_FLUSH_LEVEL.indexOf(level) !== -1) {\n flush();\n }\n }\n\n function log(level : $Values, event : string, payload = {}) : LoggerType {\n\n if (!isBrowser()) {\n return logger; // eslint-disable-line no-use-before-define\n }\n\n if (prefix) {\n event = `${ prefix }_${ event }`;\n }\n\n const logPayload : Payload = {\n ...objFilter(payload),\n timestamp: Date.now().toString()\n };\n\n for (const builder of payloadBuilders) {\n extendIfDefined(logPayload, builder(logPayload));\n }\n\n enqueue(level, event, logPayload);\n print(level, event, logPayload);\n\n return logger; // eslint-disable-line no-use-before-define\n }\n\n function addBuilder(builders, builder) : LoggerType {\n builders.push(builder);\n return logger; // eslint-disable-line no-use-before-define\n }\n\n function addPayloadBuilder(builder) : LoggerType {\n return addBuilder(payloadBuilders, builder);\n }\n\n function addMetaBuilder(builder) : LoggerType {\n return addBuilder(metaBuilders, builder);\n }\n\n function addTrackingBuilder(builder) : LoggerType {\n return addBuilder(trackingBuilders, builder);\n }\n\n function addHeaderBuilder(builder) : LoggerType {\n return addBuilder(headerBuilders, builder);\n }\n\n function debug(event, payload) : LoggerType {\n return log(LOG_LEVEL.DEBUG, event, payload);\n }\n\n function info(event, payload) : LoggerType {\n return log(LOG_LEVEL.INFO, event, payload);\n }\n\n function warn(event, payload) : LoggerType {\n return log(LOG_LEVEL.WARN, event, payload);\n }\n\n function error(event, payload) : LoggerType {\n return log(LOG_LEVEL.ERROR, event, payload);\n }\n\n function track(payload = {}) : LoggerType {\n if (!isBrowser()) {\n return logger; // eslint-disable-line no-use-before-define\n }\n\n const trackingPayload : Payload = objFilter(payload);\n\n for (const builder of trackingBuilders) {\n extendIfDefined(trackingPayload, builder(trackingPayload));\n }\n\n print(LOG_LEVEL.DEBUG, 'track', trackingPayload);\n tracking.push(trackingPayload);\n\n return logger; // eslint-disable-line no-use-before-define\n }\n\n function setTransport(newTransport : Transport) : LoggerType {\n transport = newTransport;\n return logger; // eslint-disable-line no-use-before-define\n }\n\n if (isBrowser()) {\n safeInterval(flush, flushInterval);\n }\n\n if (typeof window === 'object') {\n window.addEventListener('beforeunload', () => {\n immediateFlush();\n });\n\n window.addEventListener('unload', () => {\n immediateFlush();\n });\n }\n\n const logger = {\n debug,\n info,\n warn,\n error,\n track,\n flush,\n immediateFlush,\n addPayloadBuilder,\n addMetaBuilder,\n addTrackingBuilder,\n addHeaderBuilder,\n setTransport\n };\n\n return logger;\n}\n"],"sourceRoot":""} \ No newline at end of file diff --git a/dist/module/logger.js b/dist/module/logger.js index 1c7d356..80f2280 100644 --- a/dist/module/logger.js +++ b/dist/module/logger.js @@ -48,7 +48,9 @@ export function Logger(_ref2) { _ref2$flushInterval = _ref2.flushInterval, flushInterval = _ref2$flushInterval === void 0 ? FLUSH_INTERVAL : _ref2$flushInterval, _ref2$enableSendBeaco = _ref2.enableSendBeacon, - enableSendBeacon = _ref2$enableSendBeaco === void 0 ? false : _ref2$enableSendBeaco; + enableSendBeacon = _ref2$enableSendBeaco === void 0 ? false : _ref2$enableSendBeaco, + _ref2$enableBrowserLo = _ref2.enableBrowserLogging, + enableBrowserLogging = _ref2$enableBrowserLo === void 0 ? true : _ref2$enableBrowserLo; var events = []; var tracking = []; var payloadBuilders = []; @@ -57,7 +59,7 @@ export function Logger(_ref2) { var headerBuilders = []; function print(level, event, payload) { - if (!isBrowser() || !window.console || !window.console.log) { + if (!isBrowser() || !window.console || !window.console.log || !enableBrowserLogging) { return; } diff --git a/src/logger.js b/src/logger.js index 0a63288..c51a8a8 100644 --- a/src/logger.js +++ b/src/logger.js @@ -23,7 +23,8 @@ type LoggerOptions = {| logLevel? : $Values, transport? : Transport, flushInterval? : number, - enableSendBeacon? : boolean + enableSendBeacon? : boolean, + enableBrowserLogging? : boolean |}; type ClientPayload = { [string] : ?string | ?boolean }; @@ -72,7 +73,7 @@ function extendIfDefined(target : { [string] : string | boolean }, source : { [s } } -export function Logger({ url, prefix, logLevel = DEFAULT_LOG_LEVEL, transport = httpTransport, flushInterval = FLUSH_INTERVAL, enableSendBeacon = false } : LoggerOptions) : LoggerType { +export function Logger({ url, prefix, logLevel = DEFAULT_LOG_LEVEL, transport = httpTransport, flushInterval = FLUSH_INTERVAL, enableSendBeacon = false, enableBrowserLogging = true } : LoggerOptions) : LoggerType { let events : Array<{| level : $Values, event : string, payload : Payload |}> = []; let tracking : Array = []; @@ -84,7 +85,7 @@ export function Logger({ url, prefix, logLevel = DEFAULT_LOG_LEVEL, transport = function print(level : $Values, event : string, payload : Payload) { - if (!isBrowser() || !window.console || !window.console.log) { + if (!isBrowser() || !window.console || !window.console.log || !enableBrowserLogging) { return; } diff --git a/test/test.js b/test/test.js index 931fb1e..a111041 100644 --- a/test/test.js +++ b/test/test.js @@ -7,7 +7,6 @@ import { Logger } from '../src'; patchXmlHttpRequest(); describe('beaver-logger tests', () => { - it('should log something and flush it to the buffer', () => { // eslint-disable-next-line compat/compat window.navigator.sendBeacon = undefined; // simulate IE 11 scenario @@ -128,4 +127,71 @@ describe('beaver-logger tests', () => { } }); }); + + it('should not print logs in browser side', () => { + const loggerDB = []; + + const mockConsole = (...args) => loggerDB.push(args); + const findLoggedDBEntry = (eventName) => { + const entryLog = loggerDB.find(event => event[0] === eventName); + + if (entryLog) { + throw new Error('Expected log to not be printed in browser side'); + } + }; + + window.console.info = mockConsole; + window.console.error = mockConsole; + window.console.warn = mockConsole; + window.console.debug = mockConsole; + + const $logger = Logger({ + url: '/test/api/log', + enableBrowserLogging: false + }); + + $logger.info('test_info', { + foo: 'bar', + bar: true + }); + $logger.error('test_error', { + foo: 'bar', + bar: true + }); + $logger.warn('test_warn', { + foo: 'bar', + bar: true + }); + $logger.debug('test_debug', { + foo: 'bar', + bar: true + }); + + const logEndpoint = $mockEndpoint.register({ + method: 'POST', + uri: '/test/api/log', + handler: (req) => { + const hasLogInfo = req.data.events.some(event => event.event === 'test_info' && event.level === 'info'); + const hasLogError = req.data.events.some(event => event.event === 'test_error' && event.level === 'error'); + const hasLogWarn = req.data.events.some(event => event.event === 'test_warn' && event.level === 'warn'); + const hasLogDebug = req.data.events.some(event => event.event === 'test_debug' && event.level === 'debug'); + + if (!hasLogInfo || !hasLogError || !hasLogWarn || !hasLogDebug) { + throw new Error('Expected posted payload to contain logged log'); + } + + return {}; + } + }); + + findLoggedDBEntry('test_info'); + findLoggedDBEntry('test_error'); + findLoggedDBEntry('test_warn'); + findLoggedDBEntry('test_log'); + + logEndpoint.expectCalls(); + return $logger.flush().then(() => { + logEndpoint.done(); + }); + }); }); From a850169c3532d2cf9de5e8bcfc082b17b6dc2406 Mon Sep 17 00:00:00 2001 From: Sercan YILDIZ Date: Tue, 6 Oct 2020 13:36:32 +0200 Subject: [PATCH 2/3] Change param name disableBrowserLogging --- README.md | 4 ++-- src/logger.js | 6 +++--- test/test.js | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 78eaeb6..41b785f 100644 --- a/README.md +++ b/README.md @@ -131,8 +131,8 @@ var $logger = beaver.Logger({ // Use sendBeacon if supported rather than XHR to send logs; defaults to false enableSendBeacon: true, - // Enable logs to be displayed in the browser console - enableBrowserLogging: true + // Disable logs to be displayed in the browser console + disableBrowserLogging: true }); ``` diff --git a/src/logger.js b/src/logger.js index c51a8a8..94b044f 100644 --- a/src/logger.js +++ b/src/logger.js @@ -24,7 +24,7 @@ type LoggerOptions = {| transport? : Transport, flushInterval? : number, enableSendBeacon? : boolean, - enableBrowserLogging? : boolean + disableBrowserLogging? : boolean |}; type ClientPayload = { [string] : ?string | ?boolean }; @@ -73,7 +73,7 @@ function extendIfDefined(target : { [string] : string | boolean }, source : { [s } } -export function Logger({ url, prefix, logLevel = DEFAULT_LOG_LEVEL, transport = httpTransport, flushInterval = FLUSH_INTERVAL, enableSendBeacon = false, enableBrowserLogging = true } : LoggerOptions) : LoggerType { +export function Logger({ url, prefix, logLevel = DEFAULT_LOG_LEVEL, transport = httpTransport, flushInterval = FLUSH_INTERVAL, enableSendBeacon = false, disableBrowserLogging = false } : LoggerOptions) : LoggerType { let events : Array<{| level : $Values, event : string, payload : Payload |}> = []; let tracking : Array = []; @@ -85,7 +85,7 @@ export function Logger({ url, prefix, logLevel = DEFAULT_LOG_LEVEL, transport = function print(level : $Values, event : string, payload : Payload) { - if (!isBrowser() || !window.console || !window.console.log || !enableBrowserLogging) { + if (!isBrowser() || !window.console || !window.console.log || disableBrowserLogging) { return; } diff --git a/test/test.js b/test/test.js index a111041..e42a5a6 100644 --- a/test/test.js +++ b/test/test.js @@ -146,8 +146,8 @@ describe('beaver-logger tests', () => { window.console.debug = mockConsole; const $logger = Logger({ - url: '/test/api/log', - enableBrowserLogging: false + url: '/test/api/log', + disableBrowserLogging: true }); $logger.info('test_info', { From 497638d448f5dccb497da8c07c16055f7f4b66ce Mon Sep 17 00:00:00 2001 From: Sercan YILDIZ Date: Tue, 6 Oct 2020 13:47:55 +0200 Subject: [PATCH 3/3] Revert /dist --- dist/beaver-logger.js | 4 ++-- dist/beaver-logger.min.js | 2 +- dist/beaver-logger.min.js.map | 2 +- dist/module/logger.js | 6 ++---- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/dist/beaver-logger.js b/dist/beaver-logger.js index e08ce51..cba3a79 100644 --- a/dist/beaver-logger.js +++ b/dist/beaver-logger.js @@ -902,7 +902,7 @@ for (var key in source) source.hasOwnProperty(key) && source[key] && !target[key] && (target[key] = source[key]); } function Logger(_ref2) { - var url = _ref2.url, prefix = _ref2.prefix, _ref2$logLevel = _ref2.logLevel, logLevel = void 0 === _ref2$logLevel ? DEFAULT_LOG_LEVEL : _ref2$logLevel, _ref2$transport = _ref2.transport, transport = void 0 === _ref2$transport ? httpTransport : _ref2$transport, _ref2$flushInterval = _ref2.flushInterval, flushInterval = void 0 === _ref2$flushInterval ? 6e4 : _ref2$flushInterval, _ref2$enableSendBeaco = _ref2.enableSendBeacon, enableSendBeacon = void 0 !== _ref2$enableSendBeaco && _ref2$enableSendBeaco, _ref2$enableBrowserLo = _ref2.enableBrowserLogging, enableBrowserLogging = void 0 === _ref2$enableBrowserLo || _ref2$enableBrowserLo; + var url = _ref2.url, prefix = _ref2.prefix, _ref2$logLevel = _ref2.logLevel, logLevel = void 0 === _ref2$logLevel ? DEFAULT_LOG_LEVEL : _ref2$logLevel, _ref2$transport = _ref2.transport, transport = void 0 === _ref2$transport ? httpTransport : _ref2$transport, _ref2$flushInterval = _ref2.flushInterval, flushInterval = void 0 === _ref2$flushInterval ? 6e4 : _ref2$flushInterval, _ref2$enableSendBeaco = _ref2.enableSendBeacon, enableSendBeacon = void 0 !== _ref2$enableSendBeaco && _ref2$enableSendBeaco; var events = []; var tracking = []; var payloadBuilders = []; @@ -910,7 +910,7 @@ var trackingBuilders = []; var headerBuilders = []; function print(level, event, payload) { - if (dom_isBrowser() && window.console && window.console.log && enableBrowserLogging && !(LOG_LEVEL_PRIORITY.indexOf(level) > LOG_LEVEL_PRIORITY.indexOf(logLevel))) { + if (dom_isBrowser() && window.console && window.console.log && !(LOG_LEVEL_PRIORITY.indexOf(level) > LOG_LEVEL_PRIORITY.indexOf(logLevel))) { var args = [ event ]; args.push(payload); (payload.error || payload.warning) && args.push("\n\n", payload.error || payload.warning); diff --git a/dist/beaver-logger.min.js b/dist/beaver-logger.min.js index 294140c..f03127a 100644 --- a/dist/beaver-logger.min.js +++ b/dist/beaver-logger.min.js @@ -1,2 +1,2 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("beaver",[],t):"object"==typeof exports?exports.beaver=t():e.beaver=t()}("undefined"!=typeof self?self:this,(function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return{}.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){"use strict";function r(){return(r=Object.assign||function(e){for(var t=1;t>>0)+"__",function(){if("undefined"==typeof WeakMap)return!1;if(void 0===Object.freeze)return!1;try{var e=new WeakMap,t={};return Object.freeze(t),e.set(t,"__testvalue__"),"__testvalue__"===e.get(t)}catch(e){return!1}}())try{this.weakmap=new WeakMap}catch(e){}this.keys=[],this.values=[]}var t=e.prototype;return t._cleanupClosedWindows=function(){for(var e=this.weakmap,t=this.keys,n=0;nF.indexOf(i))){var r=[t];r.push(n),(n.error||n.warning)&&r.push("\n\n",n.error||n.warning);try{window.console[e]&&window.console[e].apply?window.console[e].apply(window.console,r):window.console.log&&window.console.log.apply&&window.console.log.apply(window.console,r)}catch(e){}}}function O(){return l.try((function(){if(N()&&window.location.protocol!==U.FILE&&(p.length||w.length)){for(var e={},n=0;n>>0)+"__",function(){if("undefined"==typeof WeakMap)return!1;if(void 0===Object.freeze)return!1;try{var e=new WeakMap,t={};return Object.freeze(t),e.set(t,"__testvalue__"),"__testvalue__"===e.get(t)}catch(e){return!1}}())try{this.weakmap=new WeakMap}catch(e){}this.keys=[],this.values=[]}var t=e.prototype;return t._cleanupClosedWindows=function(){for(var e=this.weakmap,t=this.keys,n=0;nF.indexOf(i))){var r=[t];r.push(n),(n.error||n.warning)&&r.push("\n\n",n.error||n.warning);try{window.console[e]&&window.console[e].apply?window.console[e].apply(window.console,r):window.console.log&&window.console.log.apply&&window.console.log.apply(window.console,r)}catch(e){}}}function j(){return l.try((function(){if(L()&&window.location.protocol!==U.FILE&&(h.length||v.length)){for(var e={},n=0;n) => void> = [];\n\nexport function dispatchPossiblyUnhandledError(err : mixed, promise : ZalgoPromise) {\n\n if (dispatchedErrors.indexOf(err) !== -1) {\n return;\n }\n\n dispatchedErrors.push(err);\n\n setTimeout(() => {\n if (__DEBUG__) {\n // $FlowFixMe\n throw new Error(`${ err.stack || err.toString() }\\n\\nFrom promise:\\n\\n${ promise.stack }`);\n }\n\n throw err;\n }, 1);\n\n for (let j = 0; j < possiblyUnhandledPromiseHandlers.length; j++) {\n // $FlowFixMe\n possiblyUnhandledPromiseHandlers[j](err, promise);\n }\n}\n\nexport function onPossiblyUnhandledException(handler : (mixed, promise? : ZalgoPromise) => void) : {| cancel : () => void |} {\n possiblyUnhandledPromiseHandlers.push(handler);\n\n return {\n cancel() {\n possiblyUnhandledPromiseHandlers.splice(possiblyUnhandledPromiseHandlers.indexOf(handler), 1);\n }\n };\n}\n","/* @flow */\n\nimport type { ZalgoPromise } from './promise';\n\nlet activeCount = 0;\nlet flushPromise;\n\nfunction flushActive() {\n if (!activeCount && flushPromise) {\n const promise = flushPromise;\n flushPromise = null;\n promise.resolve();\n }\n}\n\nexport function startActive() {\n activeCount += 1;\n}\n\nexport function endActive() {\n activeCount -= 1;\n flushActive();\n}\n\nexport function awaitActive(Zalgo : Class>) : ZalgoPromise { // eslint-disable-line no-undef\n const promise = flushPromise = flushPromise || new Zalgo();\n flushActive();\n return promise;\n}\n","/* @flow */\n\nimport { isPromise } from './utils';\nimport { onPossiblyUnhandledException, dispatchPossiblyUnhandledError } from './exceptions';\nimport { startActive, endActive, awaitActive } from './flush';\n\nexport class ZalgoPromise {\n\n resolved : boolean\n rejected : boolean\n errorHandled : boolean\n value : R\n error : mixed\n // eslint-disable-next-line flowtype/no-mutable-array\n handlers : Array<{|\n promise : ZalgoPromise<*>,\n onSuccess : void | (result : R) => mixed,\n onError : void | (error : mixed) => mixed\n |}>\n dispatching : boolean\n stack : string\n\n constructor(handler : ?(resolve : (result : R) => void, reject : (error : mixed) => void) => void) {\n\n this.resolved = false;\n this.rejected = false;\n this.errorHandled = false;\n\n this.handlers = [];\n\n if (handler) {\n\n let result;\n let error;\n let resolved = false;\n let rejected = false;\n let isAsync = false;\n\n startActive();\n\n try {\n handler(res => {\n if (isAsync) {\n this.resolve(res);\n } else {\n resolved = true;\n result = res;\n }\n\n }, err => {\n if (isAsync) {\n this.reject(err);\n } else {\n rejected = true;\n error = err;\n }\n });\n\n } catch (err) {\n endActive();\n this.reject(err);\n return;\n }\n\n endActive();\n\n isAsync = true;\n\n if (resolved) {\n // $FlowFixMe\n this.resolve(result);\n } else if (rejected) {\n this.reject(error);\n }\n }\n\n if (__DEBUG__) {\n try {\n throw new Error(`ZalgoPromise`);\n } catch (err) {\n this.stack = err.stack;\n }\n }\n }\n\n resolve(result : R) : ZalgoPromise {\n if (this.resolved || this.rejected) {\n return this;\n }\n\n if (isPromise(result)) {\n throw new Error('Can not resolve promise with another promise');\n }\n\n this.resolved = true;\n this.value = result;\n this.dispatch();\n\n return this;\n }\n\n reject(error : mixed) : ZalgoPromise {\n if (this.resolved || this.rejected) {\n return this;\n }\n\n if (isPromise(error)) {\n throw new Error('Can not reject promise with another promise');\n }\n\n if (!error) {\n // $FlowFixMe\n const err = (error && typeof error.toString === 'function' ? error.toString() : Object.prototype.toString.call(error));\n error = new Error(`Expected reject to be called with Error, got ${ err }`);\n }\n\n this.rejected = true;\n this.error = error;\n\n if (!this.errorHandled) {\n setTimeout(() => {\n if (!this.errorHandled) {\n dispatchPossiblyUnhandledError(error, this);\n }\n }, 1);\n }\n\n this.dispatch();\n\n return this;\n }\n\n asyncReject(error : mixed) : ZalgoPromise {\n this.errorHandled = true;\n this.reject(error);\n return this;\n }\n \n dispatch() {\n\n const { dispatching, resolved, rejected, handlers } = this;\n\n if (dispatching) {\n return;\n }\n\n if (!resolved && !rejected) {\n return;\n }\n\n this.dispatching = true;\n startActive();\n\n const chain = (firstPromise : ZalgoPromise, secondPromise : ZalgoPromise) => {\n return firstPromise.then(res => {\n secondPromise.resolve(res);\n }, err => {\n secondPromise.reject(err);\n });\n };\n\n for (let i = 0; i < handlers.length; i++) {\n\n const { onSuccess, onError, promise } = handlers[i];\n\n let result;\n\n if (resolved) {\n\n try {\n result = onSuccess ? onSuccess(this.value) : this.value;\n } catch (err) {\n promise.reject(err);\n continue;\n }\n\n } else if (rejected) {\n\n if (!onError) {\n promise.reject(this.error);\n continue;\n }\n\n try {\n result = onError(this.error);\n } catch (err) {\n promise.reject(err);\n continue;\n }\n }\n\n if (result instanceof ZalgoPromise && (result.resolved || result.rejected)) {\n\n if (result.resolved) {\n promise.resolve(result.value);\n } else {\n promise.reject(result.error);\n }\n\n result.errorHandled = true;\n\n } else if (isPromise(result)) {\n\n if (result instanceof ZalgoPromise && (result.resolved || result.rejected)) {\n if (result.resolved) {\n promise.resolve(result.value);\n } else {\n promise.reject(result.error);\n }\n\n } else {\n // $FlowFixMe\n chain(result, promise);\n }\n\n } else {\n\n promise.resolve(result);\n }\n }\n\n handlers.length = 0;\n this.dispatching = false;\n endActive();\n }\n\n then(onSuccess : void | (result : R) => (ZalgoPromise | Y), onError : void | (error : mixed) => (ZalgoPromise | Y)) : ZalgoPromise {\n\n if (onSuccess && typeof onSuccess !== 'function' && !onSuccess.call) {\n throw new Error('Promise.then expected a function for success handler');\n }\n\n if (onError && typeof onError !== 'function' && !onError.call) {\n throw new Error('Promise.then expected a function for error handler');\n }\n\n const promise : ZalgoPromise = new ZalgoPromise();\n\n this.handlers.push({\n promise,\n onSuccess,\n onError\n });\n\n this.errorHandled = true;\n\n this.dispatch();\n\n return promise;\n }\n\n catch(onError : (error : mixed) => ZalgoPromise | Y) : ZalgoPromise {\n return this.then(undefined, onError);\n }\n\n finally(onFinally : () => mixed) : ZalgoPromise {\n\n if (onFinally && typeof onFinally !== 'function' && !onFinally.call) {\n throw new Error('Promise.finally expected a function');\n }\n\n return this.then((result) => {\n return ZalgoPromise.try(onFinally)\n .then(() => {\n return result;\n });\n }, (err) => {\n return ZalgoPromise.try(onFinally)\n .then(() => {\n throw err;\n });\n });\n }\n\n timeout(time : number, err : ?Error) : ZalgoPromise {\n\n if (this.resolved || this.rejected) {\n return this;\n }\n\n const timeout = setTimeout(() => {\n\n if (this.resolved || this.rejected) {\n return;\n }\n\n this.reject(err || new Error(`Promise timed out after ${ time }ms`));\n\n }, time);\n\n return this.then(result => {\n clearTimeout(timeout);\n return result;\n });\n }\n\n // $FlowFixMe\n toPromise() : Promise {\n // $FlowFixMe\n if (typeof Promise === 'undefined') {\n throw new TypeError(`Could not find Promise`);\n }\n // $FlowFixMe\n return Promise.resolve(this); // eslint-disable-line compat/compat\n }\n\n static resolve(value : X | ZalgoPromise) : ZalgoPromise {\n\n if (value instanceof ZalgoPromise) {\n return value;\n }\n\n if (isPromise(value)) {\n // $FlowFixMe\n return new ZalgoPromise((resolve, reject) => value.then(resolve, reject));\n }\n\n return new ZalgoPromise().resolve(value);\n }\n\n static reject(error : mixed) : ZalgoPromise {\n return new ZalgoPromise().reject(error);\n }\n\n static asyncReject(error : mixed) : ZalgoPromise {\n return new ZalgoPromise().asyncReject(error);\n }\n\n static all>(promises : X) : ZalgoPromise<$TupleMap(ZalgoPromise | Y) => Y>> { // eslint-disable-line no-undef\n\n const promise = new ZalgoPromise();\n let count = promises.length;\n const results = [];\n\n if (!count) {\n promise.resolve(results);\n return promise;\n }\n\n const chain = (i : number, firstPromise : ZalgoPromise, secondPromise : ZalgoPromise) => {\n return firstPromise.then(res => {\n results[i] = res;\n count -= 1;\n if (count === 0) {\n promise.resolve(results);\n }\n }, err => {\n secondPromise.reject(err);\n });\n };\n\n for (let i = 0; i < promises.length; i++) {\n const prom = promises[i];\n\n if (prom instanceof ZalgoPromise) {\n if (prom.resolved) {\n results[i] = prom.value;\n count -= 1;\n continue;\n }\n } else if (!isPromise(prom)) {\n results[i] = prom;\n count -= 1;\n continue;\n }\n\n chain(i, ZalgoPromise.resolve(prom), promise);\n }\n\n if (count === 0) {\n promise.resolve(results);\n }\n\n return promise;\n }\n\n static hash(promises : O) : ZalgoPromise<$ObjMap(ZalgoPromise | Y) => Y>> { // eslint-disable-line no-undef\n const result = {};\n const awaitPromises = [];\n\n for (const key in promises) {\n if (promises.hasOwnProperty(key)) {\n const value = promises[key];\n\n if (isPromise(value)) {\n awaitPromises.push(value.then(res => {\n result[key] = res;\n }));\n } else {\n result[key] = value;\n }\n }\n }\n \n return ZalgoPromise.all(awaitPromises).then(() => result);\n }\n\n static map(items : $ReadOnlyArray, method : (T) => (ZalgoPromise | X)) : ZalgoPromise<$ReadOnlyArray> {\n // $FlowFixMe\n return ZalgoPromise.all(items.map(method));\n }\n\n static onPossiblyUnhandledException(handler : (err : mixed) => void) : {| cancel : () => void |} {\n return onPossiblyUnhandledException(handler);\n }\n\n static try>(method : (...args : A) => (ZalgoPromise | Y), context : ?C, args : ?A) : ZalgoPromise {\n\n if (method && typeof method !== 'function' && !method.call) {\n throw new Error('Promise.try expected a function');\n }\n\n let result;\n\n startActive();\n \n try {\n // $FlowFixMe\n result = method.apply(context, args || []);\n } catch (err) {\n endActive();\n return ZalgoPromise.reject(err);\n }\n\n endActive();\n\n return ZalgoPromise.resolve(result);\n }\n\n static delay(delay : number) : ZalgoPromise {\n return new ZalgoPromise(resolve => {\n setTimeout(resolve, delay);\n });\n }\n\n static isPromise(value : mixed) : boolean {\n\n if (value && value instanceof ZalgoPromise) {\n return true;\n }\n\n return isPromise(value);\n }\n\n static flush() : ZalgoPromise {\n return awaitActive(ZalgoPromise);\n }\n}\n","/* @flow */\n/* eslint max-lines: 0 */\n\nimport { isRegex, noop } from './util';\nimport type { CrossDomainWindowType, SameDomainWindowType, DomainMatcher } from './types';\nimport { PROTOCOL, WILDCARD } from './constants';\n\nconst IE_WIN_ACCESS_ERROR = 'Call was rejected by callee.\\r\\n';\n\nexport function isFileProtocol(win : SameDomainWindowType = window) : boolean {\n return win.location.protocol === PROTOCOL.FILE;\n}\n\nexport function isAboutProtocol(win : SameDomainWindowType = window) : boolean {\n return win.location.protocol === PROTOCOL.ABOUT;\n}\n\nexport function getParent(win? : CrossDomainWindowType = window) : ?CrossDomainWindowType {\n\n if (!win) {\n return;\n }\n\n try {\n if (win.parent && win.parent !== win) {\n return win.parent;\n }\n } catch (err) {\n // pass\n }\n}\n\nexport function getOpener(win? : CrossDomainWindowType = window) : ?CrossDomainWindowType {\n\n if (!win) {\n return;\n }\n\n // Make sure we're not actually an iframe which has had window.open() called on us\n if (getParent(win)) {\n return;\n }\n\n try {\n return win.opener;\n } catch (err) {\n // pass\n }\n}\n\nexport function canReadFromWindow(win : CrossDomainWindowType | SameDomainWindowType) : boolean {\n try {\n // $FlowFixMe\n noop(win && win.location && win.location.href);\n return true;\n } catch (err) {\n // pass\n }\n\n return false;\n}\n\nexport function getActualDomain(win? : SameDomainWindowType = window) : string {\n\n const location = win.location;\n\n if (!location) {\n throw new Error(`Can not read window location`);\n }\n\n const protocol = location.protocol;\n\n if (!protocol) {\n throw new Error(`Can not read window protocol`);\n }\n\n if (protocol === PROTOCOL.FILE) {\n return `${ PROTOCOL.FILE }//`;\n }\n\n if (protocol === PROTOCOL.ABOUT) {\n\n const parent = getParent(win);\n if (parent && canReadFromWindow(parent)) {\n // $FlowFixMe\n return getActualDomain(parent);\n }\n\n return `${ PROTOCOL.ABOUT }//`;\n }\n\n const host = location.host;\n\n if (!host) {\n throw new Error(`Can not read window host`);\n }\n\n return `${ protocol }//${ host }`;\n}\n\nexport function getDomain(win? : SameDomainWindowType = window) : string {\n\n const domain = getActualDomain(win);\n\n if (domain && win.mockDomain && win.mockDomain.indexOf(PROTOCOL.MOCK) === 0) {\n return win.mockDomain;\n }\n\n return domain;\n}\n\nexport function isBlankDomain(win : CrossDomainWindowType) : boolean {\n try {\n // $FlowFixMe\n if (!win.location.href) {\n return true;\n }\n\n if (win.location.href === 'about:blank') {\n return true;\n }\n } catch (err) {\n // pass\n }\n\n return false;\n}\n\nexport function isActuallySameDomain(win : CrossDomainWindowType) : boolean {\n\n try {\n if (win === window) {\n return true;\n }\n\n } catch (err) {\n // pass\n }\n\n try {\n const desc = Object.getOwnPropertyDescriptor(win, 'location');\n\n if (desc && desc.enumerable === false) {\n return false;\n }\n\n } catch (err) {\n // pass\n }\n\n try {\n // $FlowFixMe\n if (isAboutProtocol(win) && canReadFromWindow(win)) {\n return true;\n }\n } catch (err) {\n // pass\n }\n\n try {\n // $FlowFixMe\n if (getActualDomain(win) === getActualDomain(window)) {\n return true;\n }\n\n } catch (err) {\n // pass\n }\n\n return false;\n}\n\nexport function isSameDomain(win : CrossDomainWindowType | SameDomainWindowType) : boolean {\n\n if (!isActuallySameDomain(win)) {\n return false;\n }\n\n try {\n\n if (win === window) {\n return true;\n }\n\n // $FlowFixMe\n if (isAboutProtocol(win) && canReadFromWindow(win)) {\n return true;\n }\n\n // $FlowFixMe\n if (getDomain(window) === getDomain(win)) {\n return true;\n }\n\n } catch (err) {\n // pass\n }\n\n return false;\n}\n\n\nexport function assertSameDomain(win : CrossDomainWindowType | SameDomainWindowType) : SameDomainWindowType {\n if (!isSameDomain(win)) {\n throw new Error(`Expected window to be same domain`);\n }\n\n // $FlowFixMe\n return win;\n}\n\nexport function getParents(win : CrossDomainWindowType) : $ReadOnlyArray {\n\n const result = [];\n\n try {\n\n while (win.parent !== win) {\n result.push(win.parent);\n win = win.parent;\n }\n\n } catch (err) {\n // pass\n }\n\n return result;\n}\n\nexport function isAncestorParent(parent : CrossDomainWindowType, child : CrossDomainWindowType) : boolean {\n\n if (!parent || !child) {\n return false;\n }\n\n const childParent = getParent(child);\n\n if (childParent) {\n return childParent === parent;\n }\n\n if (getParents(child).indexOf(parent) !== -1) {\n return true;\n }\n\n return false;\n}\n\nexport function getFrames(win : CrossDomainWindowType) : $ReadOnlyArray {\n\n const result = [];\n\n let frames;\n\n try {\n frames = win.frames;\n } catch (err) {\n frames = win;\n }\n\n let len;\n\n try {\n len = frames.length;\n } catch (err) {\n // pass\n }\n\n if (len === 0) {\n return result;\n }\n\n if (len) {\n for (let i = 0; i < len; i++) {\n\n let frame;\n\n try {\n frame = frames[i];\n } catch (err) {\n continue;\n }\n\n result.push(frame);\n }\n\n return result;\n }\n\n for (let i = 0; i < 100; i++) {\n let frame;\n\n try {\n frame = frames[i];\n } catch (err) {\n return result;\n }\n\n if (!frame) {\n return result;\n }\n\n result.push(frame);\n }\n\n return result;\n}\n\n\nexport function getAllChildFrames(win : CrossDomainWindowType) : $ReadOnlyArray {\n\n const result = [];\n\n for (const frame of getFrames(win)) {\n result.push(frame);\n\n for (const childFrame of getAllChildFrames(frame)) {\n result.push(childFrame);\n }\n }\n\n return result;\n}\n\nexport function getTop(win? : CrossDomainWindowType = window) : ?CrossDomainWindowType {\n\n try {\n if (win.top) {\n return win.top;\n }\n } catch (err) {\n // pass\n }\n\n if (getParent(win) === win) {\n return win;\n }\n\n try {\n if (isAncestorParent(window, win) && window.top) {\n return window.top;\n }\n } catch (err) {\n // pass\n }\n\n try {\n if (isAncestorParent(win, window) && window.top) {\n return window.top;\n }\n } catch (err) {\n // pass\n }\n\n for (const frame of getAllChildFrames(win)) {\n try {\n if (frame.top) {\n return frame.top;\n }\n } catch (err) {\n // pass\n }\n\n if (getParent(frame) === frame) {\n return frame;\n }\n }\n}\n\nexport function getNextOpener(win? : CrossDomainWindowType = window) : ?CrossDomainWindowType {\n return getOpener(getTop(win) || win);\n}\n\nexport function getUltimateTop(win? : CrossDomainWindowType = window) : CrossDomainWindowType {\n const opener = getNextOpener(win);\n\n if (opener) {\n return getUltimateTop(opener);\n }\n\n return top;\n}\n\nexport function getAllFramesInWindow(win : CrossDomainWindowType) : $ReadOnlyArray {\n const top = getTop(win);\n\n if (!top) {\n throw new Error(`Can not determine top window`);\n }\n\n let result = [ ...getAllChildFrames(top), top ];\n\n // Win may be in shadow dom\n if (result.indexOf(win) === -1) {\n result = [ ...result, win, ...getAllChildFrames(win) ];\n }\n\n return result;\n}\n\nexport function getAllWindows(win? : CrossDomainWindowType = window) : $ReadOnlyArray {\n const frames = getAllFramesInWindow(win);\n const opener = getNextOpener(win);\n\n if (opener) {\n return [ ...getAllWindows(opener), ...frames ];\n } else {\n return frames;\n }\n}\n\nexport function isTop(win : CrossDomainWindowType) : boolean {\n return win === getTop(win);\n}\n\nexport function isFrameWindowClosed(frame : HTMLIFrameElement) : boolean {\n\n if (!frame.contentWindow) {\n return true;\n }\n\n if (!frame.parentNode) {\n return true;\n }\n\n const doc = frame.ownerDocument;\n\n if (doc && doc.documentElement && !doc.documentElement.contains(frame)) {\n let parent = frame;\n\n while (parent.parentNode && parent.parentNode !== parent) {\n parent = parent.parentNode;\n }\n\n // $FlowFixMe\n if (!parent.host || !doc.documentElement.contains(parent.host)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction safeIndexOf(collection : $ReadOnlyArray, item : T) : number {\n for (let i = 0; i < collection.length; i++) {\n\n try {\n if (collection[i] === item) {\n return i;\n }\n } catch (err) {\n // pass\n }\n }\n\n return -1;\n}\n\nconst iframeWindows = [];\nconst iframeFrames = [];\n\nexport function isWindowClosed(win : CrossDomainWindowType, allowMock : boolean = true) : boolean {\n\n try {\n if (win === window) {\n return false;\n }\n } catch (err) {\n return true;\n }\n\n try {\n if (!win) {\n return true;\n }\n\n } catch (err) {\n return true;\n }\n\n try {\n if (win.closed) {\n return true;\n }\n\n } catch (err) {\n\n // I love you so much IE\n\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return false;\n }\n\n return true;\n }\n\n\n if (allowMock && isSameDomain(win)) {\n try {\n // $FlowFixMe\n if (win.mockclosed) {\n return true;\n }\n } catch (err) {\n // pass\n }\n }\n\n // Mobile safari\n\n try {\n if (!win.parent || !win.top) {\n return true;\n }\n } catch (err) {\n // pass\n }\n\n // Yes, this actually happens in IE. win === win errors out when the window\n // is from an iframe, and the iframe was removed from the page.\n\n try {\n noop(win === win); // eslint-disable-line no-self-compare\n } catch (err) {\n return true;\n }\n\n // IE orphaned frame\n\n const iframeIndex = safeIndexOf(iframeWindows, win);\n\n if (iframeIndex !== -1) {\n const frame = iframeFrames[iframeIndex];\n\n if (frame && isFrameWindowClosed(frame)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction cleanIframes() {\n for (let i = 0; i < iframeWindows.length; i++) {\n let closed = false;\n\n try {\n closed = iframeWindows[i].closed;\n } catch (err) {\n // pass\n }\n\n if (closed) {\n iframeFrames.splice(i, 1);\n iframeWindows.splice(i, 1);\n }\n }\n}\n\nexport function linkFrameWindow(frame : HTMLIFrameElement) {\n\n cleanIframes();\n\n if (frame && frame.contentWindow) {\n try {\n iframeWindows.push(frame.contentWindow);\n iframeFrames.push(frame);\n } catch (err) {\n // pass\n }\n }\n}\n\nexport function getUserAgent(win : ?SameDomainWindowType) : string {\n win = win || window;\n return win.navigator.mockUserAgent || win.navigator.userAgent;\n}\n\n\nexport function getFrameByName(win : CrossDomainWindowType, name : string) : ?CrossDomainWindowType {\n\n const winFrames = getFrames(win);\n\n for (const childFrame of winFrames) {\n try {\n // $FlowFixMe\n if (isSameDomain(childFrame) && childFrame.name === name && winFrames.indexOf(childFrame) !== -1) {\n return childFrame;\n }\n } catch (err) {\n // pass\n }\n }\n\n try {\n // $FlowFixMe\n if (winFrames.indexOf(win.frames[name]) !== -1) {\n // $FlowFixMe\n return win.frames[name];\n }\n } catch (err) {\n // pass\n }\n\n try {\n if (winFrames.indexOf(win[name]) !== -1) {\n return win[name];\n }\n } catch (err) {\n // pass\n }\n}\n\nexport function findChildFrameByName(win : CrossDomainWindowType, name : string) : ?CrossDomainWindowType {\n\n const frame = getFrameByName(win, name);\n\n if (frame) {\n return frame;\n }\n\n for (const childFrame of getFrames(win)) {\n const namedFrame = findChildFrameByName(childFrame, name);\n\n if (namedFrame) {\n return namedFrame;\n }\n }\n}\n\nexport function findFrameByName(win : CrossDomainWindowType, name : string) : ?CrossDomainWindowType {\n const frame = getFrameByName(win, name);\n\n if (frame) {\n return frame;\n }\n\n const top = getTop(win) || win;\n\n return findChildFrameByName(top, name);\n}\n\nexport function isParent(win : CrossDomainWindowType, frame : CrossDomainWindowType) : boolean {\n\n const frameParent = getParent(frame);\n\n if (frameParent) {\n return frameParent === win;\n }\n\n for (const childFrame of getFrames(win)) {\n if (childFrame === frame) {\n return true;\n }\n }\n\n return false;\n}\n\nexport function isOpener(parent : CrossDomainWindowType, child : CrossDomainWindowType) : boolean {\n\n return parent === getOpener(child);\n}\n\nexport function getAncestor(win? : CrossDomainWindowType = window) : ?CrossDomainWindowType {\n win = win || window;\n\n const opener = getOpener(win);\n\n if (opener) {\n return opener;\n }\n\n const parent = getParent(win);\n\n if (parent) {\n return parent;\n }\n}\n\nexport function getAncestors(win : CrossDomainWindowType) : $ReadOnlyArray {\n\n const results = [];\n\n let ancestor = win;\n\n while (ancestor) {\n ancestor = getAncestor(ancestor);\n if (ancestor) {\n results.push(ancestor);\n }\n }\n\n return results;\n}\n\n\nexport function isAncestor(parent : CrossDomainWindowType, child : CrossDomainWindowType) : boolean {\n\n const actualParent = getAncestor(child);\n\n if (actualParent) {\n if (actualParent === parent) {\n return true;\n }\n\n return false;\n }\n\n if (child === parent) {\n return false;\n }\n\n if (getTop(child) === child) {\n return false;\n }\n\n for (const frame of getFrames(parent)) {\n if (frame === child) {\n return true;\n }\n }\n\n return false;\n}\n\nexport function isPopup(win? : CrossDomainWindowType = window) : boolean {\n return Boolean(getOpener(win));\n}\n\nexport function isIframe(win? : CrossDomainWindowType = window) : boolean {\n return Boolean(getParent(win));\n}\n\nexport function isFullpage(win? : CrossDomainWindowType = window) : boolean {\n return Boolean(!isIframe(win) && !isPopup(win));\n}\n\nfunction anyMatch(collection1, collection2) : boolean {\n\n for (const item1 of collection1) {\n for (const item2 of collection2) {\n if (item1 === item2) {\n return true;\n }\n }\n }\n\n return false;\n}\n\nexport function getDistanceFromTop(win : CrossDomainWindowType = window) : number {\n let distance = 0;\n let parent = win;\n\n while (parent) {\n parent = getParent(parent);\n if (parent) {\n distance += 1;\n }\n }\n\n return distance;\n}\n\nexport function getNthParent(win : CrossDomainWindowType, n : number = 1) : ?CrossDomainWindowType {\n let parent = win;\n\n for (let i = 0; i < n; i++) {\n if (!parent) {\n return;\n }\n\n parent = getParent(parent);\n }\n\n return parent;\n}\n\nexport function getNthParentFromTop(win : CrossDomainWindowType, n : number = 1) : ?CrossDomainWindowType {\n return getNthParent(win, getDistanceFromTop(win) - n);\n}\n\nexport function isSameTopWindow(win1 : CrossDomainWindowType, win2 : CrossDomainWindowType) : boolean {\n\n const top1 = getTop(win1) || win1;\n const top2 = getTop(win2) || win2;\n\n try {\n if (top1 && top2) {\n if (top1 === top2) {\n return true;\n }\n\n return false;\n }\n } catch (err) {\n // pass\n }\n\n const allFrames1 = getAllFramesInWindow(win1);\n const allFrames2 = getAllFramesInWindow(win2);\n\n if (anyMatch(allFrames1, allFrames2)) {\n return true;\n }\n\n const opener1 = getOpener(top1);\n const opener2 = getOpener(top2);\n\n if (opener1 && anyMatch(getAllFramesInWindow(opener1), allFrames2)) {\n return false;\n }\n\n if (opener2 && anyMatch(getAllFramesInWindow(opener2), allFrames1)) {\n return false;\n }\n\n return false;\n}\n\nexport function matchDomain(pattern : DomainMatcher, origin : DomainMatcher) : boolean {\n\n if (typeof pattern === 'string') {\n\n if (typeof origin === 'string') {\n return pattern === WILDCARD || origin === pattern;\n }\n\n if (isRegex(origin)) {\n return false;\n }\n\n if (Array.isArray(origin)) {\n return false;\n }\n }\n\n if (isRegex(pattern)) {\n\n if (isRegex(origin)) {\n return pattern.toString() === origin.toString();\n }\n\n if (Array.isArray(origin)) {\n return false;\n }\n\n // $FlowFixMe\n return Boolean(origin.match(pattern));\n }\n\n if (Array.isArray(pattern)) {\n\n if (Array.isArray(origin)) {\n return JSON.stringify(pattern) === JSON.stringify(origin);\n }\n\n if (isRegex(origin)) {\n return false;\n }\n\n return pattern.some(subpattern => matchDomain(subpattern, origin));\n }\n\n return false;\n}\n\nexport function stringifyDomainPattern(pattern : DomainMatcher) : string {\n if (Array.isArray(pattern)) {\n return `(${ pattern.join(' | ') })`;\n } else if (isRegex(pattern)) {\n return `RegExp(${ pattern.toString() }`;\n } else {\n return pattern.toString();\n }\n}\n\nexport function getDomainFromUrl(url : string) : string {\n\n let domain;\n\n if (url.match(/^(https?|mock|file):\\/\\//)) {\n domain = url;\n } else {\n return getDomain();\n }\n\n domain = domain.split('/').slice(0, 3).join('/');\n\n return domain;\n}\n\nexport function onCloseWindow(win : CrossDomainWindowType, callback : Function, delay : number = 1000, maxtime : number = Infinity) : {| cancel : () => void |} {\n\n let timeout;\n\n const check = () => {\n\n if (isWindowClosed(win)) {\n\n if (timeout) {\n clearTimeout(timeout);\n }\n\n return callback();\n }\n\n if (maxtime <= 0) {\n clearTimeout(timeout);\n } else {\n maxtime -= delay;\n timeout = setTimeout(check, delay);\n }\n };\n\n check();\n\n return {\n cancel() {\n if (timeout) {\n clearTimeout(timeout);\n }\n }\n };\n}\n\n// eslint-disable-next-line complexity\nexport function isWindow(obj : Object) : boolean {\n\n try {\n if (obj === window) {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (Object.prototype.toString.call(obj) === '[object Window]') {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (window.Window && obj instanceof window.Window) {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (obj && obj.self === obj) {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (obj && obj.parent === obj) {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (obj && obj.top === obj) {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (noop(obj === obj) === '__unlikely_value__') { // eslint-disable-line no-self-compare\n return false;\n }\n\n } catch (err) {\n return true;\n }\n\n try {\n if (obj && obj.__cross_domain_utils_window_check__ === '__unlikely_value__') {\n return false;\n }\n\n } catch (err) {\n return true;\n }\n\n try {\n if ('postMessage' in obj && 'self' in obj && 'location' in obj) {\n return true;\n }\n } catch (err) {\n // pass\n }\n\n return false;\n}\n\nexport function isBrowser() : boolean {\n return (typeof window !== 'undefined' && typeof window.location !== 'undefined');\n}\n\nexport function isCurrentDomain(domain : string) : boolean {\n if (!isBrowser()) {\n return false;\n }\n\n return (getDomain() === domain);\n}\n\nexport function isMockDomain(domain : string) : boolean {\n return domain.indexOf(PROTOCOL.MOCK) === 0;\n}\n\nexport function normalizeMockUrl(url : string) : string {\n if (!isMockDomain(getDomainFromUrl(url))) {\n return url;\n }\n\n if (!__TEST__) {\n throw new Error(`Mock urls not supported out of test mode`);\n }\n\n return url.replace(/^mock:\\/\\/[^/]+/, getActualDomain(window));\n}\n\nexport function closeWindow(win : CrossDomainWindowType) {\n try {\n win.close();\n } catch (err) {\n // pass\n }\n}\n\nexport function getFrameForWindow(win : CrossDomainWindowType) : ?HTMLElement {\n if (isSameDomain(win)) {\n return assertSameDomain(win).frameElement;\n }\n\n for (const frame of document.querySelectorAll('iframe')) {\n if (frame && frame.contentWindow && frame.contentWindow === win) {\n return frame;\n }\n }\n}\n","/* @flow */\n\nexport const PROTOCOL = {\n MOCK: ('mock:' : 'mock:'),\n FILE: ('file:' : 'file:'),\n ABOUT: ('about:' : 'about:')\n};\n\nexport const WILDCARD = '*';\n\nexport const WINDOW_TYPE = {\n IFRAME: ('iframe' : 'iframe'),\n POPUP: ('popup' : 'popup')\n};\n","/* @flow */\n\nexport function safeIndexOf(collection : $ReadOnlyArray, item : T) : number {\n for (let i = 0; i < collection.length; i++) {\n\n try {\n if (collection[i] === item) {\n return i;\n }\n } catch (err) {\n // pass\n }\n }\n\n return -1;\n}\n\n// eslint-disable-next-line no-unused-vars\nexport function noop(...args : $ReadOnlyArray) {\n // pass\n}\n","/* @flow */\n\nimport { isWindow, isWindowClosed } from 'cross-domain-utils/src';\n\nimport { hasNativeWeakMap } from './native';\nimport { noop, safeIndexOf } from './util';\n\nexport class CrossDomainSafeWeakMap {\n\n name : string\n weakmap : ?WeakMap\n // eslint-disable-next-line flowtype/no-mutable-array\n keys : Array\n // eslint-disable-next-line flowtype/no-mutable-array\n values : Array\n\n constructor() {\n // eslint-disable-next-line no-bitwise\n this.name = `__weakmap_${ Math.random() * 1e9 >>> 0 }__`;\n\n if (hasNativeWeakMap()) {\n try {\n this.weakmap = new WeakMap();\n } catch (err) {\n // pass\n }\n }\n\n this.keys = [];\n this.values = [];\n }\n\n _cleanupClosedWindows() {\n\n const weakmap = this.weakmap;\n const keys = this.keys;\n\n for (let i = 0; i < keys.length; i++) {\n const value = keys[i];\n\n if (isWindow(value) && isWindowClosed(value)) {\n\n if (weakmap) {\n try {\n weakmap.delete(value);\n } catch (err) {\n // pass\n }\n }\n\n keys.splice(i, 1);\n this.values.splice(i, 1);\n\n i -= 1;\n }\n }\n }\n\n isSafeToReadWrite(key : K) : boolean {\n\n if (isWindow(key)) {\n return false;\n }\n\n try {\n noop(key && key.self);\n noop(key && key[this.name]);\n } catch (err) {\n return false;\n }\n\n return true;\n }\n\n set(key : K, value : V) {\n\n if (!key) {\n throw new Error(`WeakMap expected key`);\n }\n\n const weakmap = this.weakmap;\n\n if (weakmap) {\n try {\n weakmap.set(key, value);\n } catch (err) {\n delete this.weakmap;\n }\n }\n\n if (this.isSafeToReadWrite(key)) {\n try {\n const name = this.name;\n const entry = key[name];\n\n if (entry && entry[0] === key) {\n entry[1] = value;\n } else {\n Object.defineProperty(key, name, {\n value: [ key, value ],\n writable: true\n });\n }\n\n return;\n\n } catch (err) {\n // pass\n }\n }\n\n this._cleanupClosedWindows();\n\n const keys = this.keys;\n const values = this.values;\n const index = safeIndexOf(keys, key);\n\n if (index === -1) {\n keys.push(key);\n values.push(value);\n } else {\n values[index] = value;\n }\n }\n\n get(key : K) : V | void {\n\n if (!key) {\n throw new Error(`WeakMap expected key`);\n }\n\n const weakmap = this.weakmap;\n\n if (weakmap) {\n try {\n if (weakmap.has(key)) {\n return weakmap.get(key);\n }\n \n } catch (err) {\n delete this.weakmap;\n }\n }\n\n if (this.isSafeToReadWrite(key)) {\n try {\n const entry = key[this.name];\n\n if (entry && entry[0] === key) {\n return entry[1];\n }\n\n return;\n } catch (err) {\n // pass\n }\n }\n\n this._cleanupClosedWindows();\n\n const keys = this.keys;\n const index = safeIndexOf(keys, key);\n\n if (index === -1) {\n return;\n }\n\n return this.values[index];\n }\n\n delete(key : K) {\n\n if (!key) {\n throw new Error(`WeakMap expected key`);\n }\n\n const weakmap = this.weakmap;\n\n if (weakmap) {\n try {\n weakmap.delete(key);\n } catch (err) {\n delete this.weakmap;\n }\n }\n\n if (this.isSafeToReadWrite(key)) {\n try {\n const entry = key[this.name];\n\n if (entry && entry[0] === key) {\n entry[0] = entry[1] = undefined;\n }\n } catch (err) {\n // pass\n }\n }\n\n this._cleanupClosedWindows();\n\n const keys = this.keys;\n const index = safeIndexOf(keys, key);\n\n if (index !== -1) {\n keys.splice(index, 1);\n this.values.splice(index, 1);\n }\n }\n\n has(key : K) : boolean {\n\n if (!key) {\n throw new Error(`WeakMap expected key`);\n }\n\n const weakmap = this.weakmap;\n\n if (weakmap) {\n try {\n if (weakmap.has(key)) {\n return true;\n }\n } catch (err) {\n delete this.weakmap;\n }\n }\n\n if (this.isSafeToReadWrite(key)) {\n try {\n const entry = key[this.name];\n\n if (entry && entry[0] === key) {\n return true;\n }\n\n return false;\n } catch (err) {\n // pass\n }\n }\n\n this._cleanupClosedWindows();\n\n const index = safeIndexOf(this.keys, key);\n return index !== -1;\n }\n\n getOrSet(key : K, getter : () => V) : V {\n if (this.has(key)) {\n // $FlowFixMe\n return this.get(key);\n }\n\n const value = getter();\n this.set(key, value);\n return value;\n }\n}\n","\n/* @flow */\n/* eslint max-lines: 0 */\n\nimport { ZalgoPromise } from 'zalgo-promise/src';\nimport { WeakMap } from 'cross-domain-safe-weakmap/src';\n\nimport type { CancelableType } from './types';\n\nexport function getFunctionName (fn : T) : string {\n return fn.name || fn.__name__ || fn.displayName || 'anonymous';\n}\n\nexport function setFunctionName (fn : T, name : string) : T {\n try {\n delete fn.name;\n fn.name = name;\n } catch (err) {\n // pass\n }\n\n fn.__name__ = fn.displayName = name;\n return fn;\n}\n\nexport function base64encode(str : string) : string {\n if (typeof btoa === 'function') {\n return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (m, p1) => {\n return String.fromCharCode(parseInt(p1, 16));\n }));\n }\n\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(str, 'utf8').toString('base64');\n }\n\n throw new Error(`Can not find window.btoa or Buffer`);\n}\n\nexport function base64decode(str : string) : string {\n if (typeof atob === 'function') {\n return decodeURIComponent(Array.prototype.map.call(atob(str), c => {\n // eslint-disable-next-line prefer-template\n return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);\n }).join(''));\n }\n\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(str, 'base64').toString('utf8');\n }\n\n throw new Error(`Can not find window.atob or Buffer`);\n}\n\nexport function uniqueID() : string {\n\n const chars = '0123456789abcdef';\n\n const randomID = 'xxxxxxxxxx'.replace(/./g, () => {\n return chars.charAt(Math.floor(Math.random() * chars.length));\n });\n\n const timeID = base64encode(\n new Date().toISOString().slice(11, 19).replace('T', '.')\n ).replace(/[^a-zA-Z0-9]/g, '').toLowerCase();\n\n return `${ randomID }_${ timeID }`;\n}\n\nexport function getGlobal() : Object {\n if (typeof window !== 'undefined') {\n return window;\n }\n if (typeof global !== 'undefined') {\n return global;\n }\n if (typeof __GLOBAL__ !== 'undefined') {\n return __GLOBAL__;\n }\n throw new Error(`No global found`);\n}\n\nlet objectIDs;\n\nexport function getObjectID(obj : Object) : string {\n\n objectIDs = objectIDs || new WeakMap();\n\n if (obj === null || obj === undefined || (typeof obj !== 'object' && typeof obj !== 'function')) {\n throw new Error(`Invalid object`);\n }\n\n let uid = objectIDs.get(obj);\n\n if (!uid) {\n uid = `${ typeof obj }:${ uniqueID() }`;\n objectIDs.set(obj, uid);\n }\n\n return uid;\n}\n\nfunction serializeArgs(args : $ReadOnlyArray) : string {\n try {\n return JSON.stringify(Array.prototype.slice.call(args), (subkey, val) => {\n if (typeof val === 'function') {\n return `memoize[${ getObjectID(val) }]`;\n }\n return val;\n });\n } catch (err) {\n throw new Error(`Arguments not serializable -- can not be used to memoize`);\n }\n}\ntype MemoizeOptions = {|\n name? : string,\n time? : number,\n thisNamespace? : boolean\n|};\n\nconst getDefaultMemoizeOptions = () : MemoizeOptions => {\n // $FlowFixMe\n return {};\n};\n\nconst memoizedFunctions = [];\n\nexport function memoize(method : F, options? : MemoizeOptions = getDefaultMemoizeOptions()) : F & {| reset : () => void |} {\n const cacheMap = new WeakMap();\n\n const memoizedFunction = function memoizedFunction(...args) : mixed {\n const cache = cacheMap.getOrSet(options.thisNamespace ? this : method, () => ({}));\n\n const key : string = serializeArgs(args);\n\n const cacheTime = options.time;\n if (cache[key] && cacheTime && (Date.now() - cache[key].time) < cacheTime) {\n delete cache[key];\n }\n\n if (cache[key]) {\n return cache[key].value;\n }\n\n const time = Date.now();\n const value = method.apply(this, arguments);\n\n cache[key] = { time, value };\n\n return cache[key].value;\n };\n\n memoizedFunction.reset = () => {\n cacheMap.delete(options.thisNamespace ? this : method);\n };\n\n memoizedFunctions.push(memoizedFunction);\n\n // $FlowFixMe\n const result : F = memoizedFunction;\n\n return setFunctionName(result, `${ options.name || getFunctionName(method) }::memoized`);\n}\n\nmemoize.clear = () => {\n for (const memoizedFunction of memoizedFunctions) {\n memoizedFunction.reset();\n }\n};\n\nexport function promiseIdentity(item : ZalgoPromise | T) : ZalgoPromise {\n // $FlowFixMe\n return ZalgoPromise.resolve(item);\n}\n\n// eslint-disable-next-line flowtype/no-weak-types\nexport function memoizePromise(method : (...args : $ReadOnlyArray) => ZalgoPromise) : ((...args : $ReadOnlyArray) => ZalgoPromise) {\n let cache = {};\n\n // eslint-disable-next-line flowtype/no-weak-types\n function memoizedPromiseFunction(...args : $ReadOnlyArray) : ZalgoPromise {\n const key : string = serializeArgs(args);\n\n if (cache.hasOwnProperty(key)) {\n return cache[key];\n }\n\n cache[key] = ZalgoPromise.try(() => method.apply(this, arguments))\n .finally(() => {\n delete cache[key];\n });\n\n return cache[key];\n }\n\n memoizedPromiseFunction.reset = () => {\n cache = {};\n };\n\n return setFunctionName(memoizedPromiseFunction, `${ getFunctionName(method) }::promiseMemoized`);\n}\n\ntype PromisifyOptions = {|\n name ? : string\n|};\n\nconst getDefaultPromisifyOptions = () : PromisifyOptions => {\n // $FlowFixMe\n return {};\n};\n\n// eslint-disable-next-line flowtype/no-weak-types\nexport function promisify(method : (...args : $ReadOnlyArray) => R, options : PromisifyOptions = getDefaultPromisifyOptions()) : ((...args : $ReadOnlyArray) => ZalgoPromise) {\n function promisifiedFunction() : ZalgoPromise {\n return ZalgoPromise.try(method, this, arguments);\n }\n\n if (options.name) {\n promisifiedFunction.displayName = `${ options.name }:promisified`;\n }\n\n return setFunctionName(promisifiedFunction, `${ getFunctionName(method) }::promisified`);\n}\n\n// eslint-disable-next-line flowtype/no-weak-types\nexport function inlineMemoize(method : (...args : $ReadOnlyArray) => R, logic : (...args : $ReadOnlyArray) => R, args : $ReadOnlyArray = []) : R {\n // $FlowFixMe\n const cache : {| [string] : R |} = method.__inline_memoize_cache__ = method.__inline_memoize_cache__ || {};\n const key = serializeArgs(args);\n\n if (cache.hasOwnProperty(key)) {\n return cache[key];\n }\n \n const result = cache[key] = logic(...args);\n\n return result;\n}\n\n// eslint-disable-next-line no-unused-vars\nexport function noop(...args : $ReadOnlyArray) {\n // pass\n}\n\nexport function once(method : Function) : Function {\n let called = false;\n\n const onceFunction = function() : mixed {\n if (!called) {\n called = true;\n return method.apply(this, arguments);\n }\n };\n\n return setFunctionName(onceFunction, `${ getFunctionName(method) }::once`);\n}\n\nexport function hashStr(str : string) : number {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n hash += str[i].charCodeAt(0) * Math.pow((i % 10) + 1, 5);\n }\n return Math.floor(Math.pow(Math.sqrt(hash), 5));\n}\n\nexport function strHashStr(str : string) : string {\n let hash = '';\n\n for (let i = 0; i < str.length; i++) {\n let total = (str[i].charCodeAt(0) * i);\n\n if (str[i + 1]) {\n total += (str[i + 1].charCodeAt(0) * (i - 1));\n }\n\n hash += String.fromCharCode(97 + (Math.abs(total) % 26));\n }\n\n return hash;\n}\n\nexport function match(str : string, pattern : RegExp) : ?string {\n const regmatch = str.match(pattern);\n if (regmatch) {\n return regmatch[1];\n }\n}\n\nexport function awaitKey(obj : Object, key : string) : ZalgoPromise {\n return new ZalgoPromise(resolve => {\n\n let value = obj[key];\n\n if (value) {\n return resolve(value);\n }\n\n delete obj[key];\n\n Object.defineProperty(obj, key, {\n\n configurable: true,\n\n set(item) {\n value = item;\n\n if (value) {\n resolve(value);\n }\n },\n\n get() : T {\n return value;\n }\n });\n });\n}\n\nexport function stringifyError(err : mixed, level : number = 1) : string {\n\n if (level >= 3) {\n return 'stringifyError stack overflow';\n }\n\n try {\n if (!err) {\n return ``;\n }\n\n if (typeof err === 'string') {\n return err;\n }\n\n if (err instanceof Error) {\n const stack = err && err.stack;\n const message = err && err.message;\n\n if (stack && message) {\n if (stack.indexOf(message) !== -1) {\n return stack;\n } else {\n return `${ message }\\n${ stack }`;\n }\n } else if (stack) {\n return stack;\n } else if (message) {\n return message;\n }\n }\n\n if (err && err.toString && typeof err.toString === 'function') {\n // $FlowFixMe\n return err.toString();\n }\n\n return Object.prototype.toString.call(err);\n\n } catch (newErr) {\n return `Error while stringifying error: ${ stringifyError(newErr, level + 1) }`;\n }\n}\n\nexport function stringifyErrorMessage(err : mixed) : string {\n\n const defaultMessage = ``;\n\n if (!err) {\n return defaultMessage;\n }\n\n if (err instanceof Error) {\n return err.message || defaultMessage;\n }\n\n if (typeof err.message === 'string') {\n return err.message || defaultMessage;\n }\n\n return defaultMessage;\n}\n\nexport function stringify(item : mixed) : string {\n if (typeof item === 'string') {\n return item;\n }\n\n if (item && item.toString && typeof item.toString === 'function') {\n // $FlowFixMe\n return item.toString();\n }\n\n return Object.prototype.toString.call(item);\n}\n\nexport function domainMatches(hostname : string, domain : string) : boolean {\n hostname = hostname.split('://')[1];\n const index = hostname.indexOf(domain);\n return (index !== -1 && hostname.slice(index) === domain);\n}\n\nexport function patchMethod(obj : Object, name : string, handler : Function) {\n const original = obj[name];\n\n obj[name] = function patchedMethod() : mixed {\n return handler({\n context: this,\n args: Array.prototype.slice.call(arguments),\n original,\n callOriginal: () => original.apply(this, arguments)\n });\n };\n}\n\nexport function extend(obj : T, source : Object) : T {\n if (!source) {\n return obj;\n }\n\n if (Object.assign) {\n return Object.assign(obj, source);\n }\n\n for (const key in source) {\n if (source.hasOwnProperty(key)) {\n obj[key] = source[key];\n }\n }\n\n return obj;\n}\n\n// eslint-disable-next-line no-undef\ntype Values = ({ [string] : T }) => $ReadOnlyArray;\n\nexport const values : Values = (obj) => {\n if (Object.values) {\n // $FlowFixMe\n return Object.values(obj);\n }\n\n const result = [];\n for (const key in obj) {\n if (obj.hasOwnProperty(key)) {\n result.push(obj[key]);\n }\n }\n\n // $FlowFixMe\n return result;\n};\n\nexport const memoizedValues : Values = memoize(values);\n\nexport function perc(pixels : number, percentage : number) : number {\n return Math.round((pixels * percentage) / 100);\n}\n\nexport function min(...args : $ReadOnlyArray) : number {\n return Math.min(...args);\n}\n\nexport function max(...args : $ReadOnlyArray) : number {\n return Math.max(...args);\n}\n\nexport function regexMap(str : string, regexp : RegExp, handler : () => T) : $ReadOnlyArray {\n const results = [];\n\n // $FlowFixMe\n str.replace(regexp, function regexMapMatcher(item) {\n results.push(handler ? handler.apply(null, arguments) : item);\n });\n\n // $FlowFixMe\n return results;\n}\n\nexport function svgToBase64(svg : string) : string {\n return `data:image/svg+xml;base64,${ base64encode(svg) }`;\n}\n\nexport function objFilter(obj : { [string] : T }, filter? : (T, ?string) => mixed = Boolean) : { [string] : R } {\n const result = {};\n\n for (const key in obj) {\n if (!obj.hasOwnProperty(key) || !filter(obj[key], key)) {\n continue;\n }\n\n result[key] = obj[key];\n }\n\n return result;\n}\n\nexport function identity (item : T) : T {\n return item;\n}\n\nexport function regexTokenize(text : string, regexp : RegExp) : $ReadOnlyArray {\n const result = [];\n text.replace(regexp, token => {\n result.push(token);\n return '';\n });\n return result;\n}\n\nexport function promiseDebounce(method : () => ZalgoPromise | T, delay : number = 50) : () => ZalgoPromise {\n\n let promise;\n let timeout;\n\n const promiseDebounced = function() : ZalgoPromise {\n if (timeout) {\n clearTimeout(timeout);\n }\n\n const localPromise = promise = promise || new ZalgoPromise();\n\n timeout = setTimeout(() => {\n promise = null;\n timeout = null;\n\n ZalgoPromise.try(method).then(\n result => { localPromise.resolve(result); },\n err => { localPromise.reject(err); }\n );\n }, delay);\n\n return localPromise;\n };\n\n return setFunctionName(promiseDebounced, `${ getFunctionName(method) }::promiseDebounced`);\n}\n\nexport function safeInterval(method : Function, time : number) : {| cancel : () => void |} {\n\n let timeout;\n\n function loop() {\n timeout = setTimeout(() => {\n method();\n loop();\n }, time);\n }\n\n loop();\n\n return {\n cancel() {\n clearTimeout(timeout);\n }\n };\n}\n\nexport function isInteger(str : string) : boolean {\n return Boolean(str.match(/^[0-9]+$/));\n}\n\nexport function isFloat(str : string) : boolean {\n return Boolean(str.match(/^[0-9]+\\.[0-9]+$/));\n}\n\nexport function serializePrimitive(value : string | number | boolean) : string {\n return value.toString();\n}\n\nexport function deserializePrimitive(value : string) : string | number | boolean {\n if (value === 'true') {\n return true;\n } else if (value === 'false') {\n return false;\n } else if (isInteger(value)) {\n return parseInt(value, 10);\n } else if (isFloat(value)) {\n return parseFloat(value);\n } else {\n return value;\n }\n}\n\nexport function dotify(obj : Object, prefix : string = '', newobj : Object = {}) : { [string] : string } {\n prefix = prefix ? `${ prefix }.` : prefix;\n for (const key in obj) {\n if (!obj.hasOwnProperty(key) || obj[key] === undefined || obj[key] === null || typeof obj[key] === 'function') {\n continue;\n } else if (obj[key] && Array.isArray(obj[key]) && obj[key].length && obj[key].every(val => typeof val !== 'object')) {\n newobj[`${ prefix }${ key }[]`] = obj[key].join(',');\n } else if (obj[key] && typeof obj[key] === 'object') {\n newobj = dotify(obj[key], `${ prefix }${ key }`, newobj);\n } else {\n newobj[`${ prefix }${ key }`] = serializePrimitive(obj[key]);\n }\n }\n return newobj;\n}\n\nexport function undotify(obj : { [string] : string }) : Object {\n \n const result = {};\n\n for (let key in obj) {\n if (!obj.hasOwnProperty(key) || typeof obj[key] !== 'string') {\n continue;\n }\n\n let value = obj[key];\n\n if (key.match(/^.+\\[\\]$/)) {\n key = key.slice(0, -2);\n value = value.split(',').map(deserializePrimitive);\n } else {\n value = deserializePrimitive(value);\n }\n\n let keyResult = result;\n const parts = key.split('.');\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n const isLast = (i + 1 === parts.length);\n const isIndex = !isLast && isInteger(parts[i + 1]);\n\n if (part === 'constructor' || part === 'prototype' || part === '__proto__') {\n throw new Error(`Disallowed key: ${ part }`);\n }\n\n if (isLast) {\n // $FlowFixMe\n keyResult[part] = value;\n } else {\n // $FlowFixMe\n keyResult = keyResult[part] = keyResult[part] || (isIndex ? [] : {});\n }\n }\n }\n\n return result;\n}\n\nexport type EventEmitterType = {|\n on : (eventName : string, handler : Function) => CancelableType,\n once : (eventName : string, handler : Function) => CancelableType,\n trigger : (eventName : string, ...args : $ReadOnlyArray) => ZalgoPromise,\n triggerOnce : (eventName : string, ...args : $ReadOnlyArray) => ZalgoPromise,\n reset : () => void\n|};\n\nexport function eventEmitter() : EventEmitterType {\n const triggered = {};\n let handlers = {};\n\n return {\n\n on(eventName : string, handler : Function) : CancelableType {\n const handlerList = handlers[eventName] = handlers[eventName] || [];\n\n handlerList.push(handler);\n\n let cancelled = false;\n\n return {\n cancel() {\n if (!cancelled) {\n cancelled = true;\n handlerList.splice(handlerList.indexOf(handler), 1);\n }\n\n }\n };\n },\n\n once(eventName : string, handler : Function) : CancelableType {\n\n const listener = this.on(eventName, () => {\n listener.cancel();\n handler();\n });\n\n return listener;\n },\n\n trigger(eventName : string, ...args : $ReadOnlyArray) : ZalgoPromise {\n\n const handlerList = handlers[eventName];\n const promises = [];\n\n if (handlerList) {\n for (const handler of handlerList) {\n promises.push(ZalgoPromise.try(() => handler(...args)));\n }\n }\n\n return ZalgoPromise.all(promises).then(noop);\n },\n\n triggerOnce(eventName : string, ...args : $ReadOnlyArray) : ZalgoPromise {\n\n if (triggered[eventName]) {\n return ZalgoPromise.resolve();\n }\n\n triggered[eventName] = true;\n return this.trigger(eventName, ...args);\n },\n\n reset() {\n handlers = {};\n }\n };\n}\n\nexport function camelToDasherize(string : string) : string {\n return string.replace(/([A-Z])/g, (g) => {\n return `-${ g.toLowerCase() }`;\n });\n}\n\nexport function dasherizeToCamel(string : string) : string {\n return string.replace(/-([a-z])/g, (g) => {\n return g[1].toUpperCase();\n });\n}\n\nexport function capitalizeFirstLetter(string : string) : string {\n return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();\n}\n\nexport function get(item : Object, path : string, def : mixed) : mixed {\n\n if (!path) {\n return def;\n }\n\n const pathParts = path.split('.');\n\n // Loop through each section of our key path\n\n for (let i = 0; i < pathParts.length; i++) {\n\n // If we have an object, we can get the key\n if (typeof item === 'object' && item !== null) {\n item = item[pathParts[i]];\n\n // Otherwise, we should return the default (undefined if not provided)\n } else {\n return def;\n }\n }\n\n // If our final result is undefined, we should return the default\n\n return item === undefined ? def : item;\n}\n\nexport function safeTimeout(method : Function, time : number) {\n\n const interval = safeInterval(() => {\n time -= 100;\n if (time <= 0) {\n interval.cancel();\n method();\n }\n }, 100);\n}\n\nexport function defineLazyProp(obj : Object | $ReadOnlyArray, key : string | number, getter : () => T) {\n if (Array.isArray(obj)) {\n if (typeof key !== 'number') {\n throw new TypeError(`Array key must be number`);\n }\n } else if (typeof obj === 'object' && obj !== null) {\n if (typeof key !== 'string') {\n throw new TypeError(`Object key must be string`);\n }\n }\n \n Object.defineProperty(obj, key, {\n configurable: true,\n enumerable: true,\n get: () => {\n // $FlowFixMe\n delete obj[key];\n const value = getter();\n // $FlowFixMe\n obj[key] = value;\n return value;\n },\n set: (value : T) => {\n // $FlowFixMe\n delete obj[key];\n // $FlowFixMe\n obj[key] = value;\n }\n });\n}\n\nexport function arrayFrom(item : Iterable) : $ReadOnlyArray { // eslint-disable-line no-undef\n return Array.prototype.slice.call(item);\n}\n\nexport function isObject(item : mixed) : boolean {\n return (typeof item === 'object' && item !== null);\n}\n\nexport function isObjectObject(obj : mixed) : boolean {\n return isObject(obj) && Object.prototype.toString.call(obj) === '[object Object]';\n}\n\nexport function isPlainObject(obj : mixed) : boolean {\n if (!isObjectObject(obj)) {\n return false;\n }\n\n // $FlowFixMe\n const constructor = obj.constructor;\n\n if (typeof constructor !== 'function') {\n return false;\n }\n\n const prototype = constructor.prototype;\n\n if (!isObjectObject(prototype)) {\n return false;\n }\n\n if (!prototype.hasOwnProperty('isPrototypeOf')) {\n return false;\n }\n\n return true;\n}\n\nexport function replaceObject | Object> (item : T, replacer : (mixed, string | number, string) => mixed, fullKey : string = '') : T {\n\n if (Array.isArray(item)) {\n const length = item.length;\n const result : Array = [];\n\n for (let i = 0; i < length; i++) {\n\n \n defineLazyProp(result, i, () => {\n const itemKey = fullKey ? `${ fullKey }.${ i }` : `${ i }`;\n const el = item[i];\n\n let child = replacer(el, i, itemKey);\n\n if (isPlainObject(child) || Array.isArray(child)) {\n // $FlowFixMe\n child = replaceObject(child, replacer, itemKey);\n }\n\n return child;\n });\n }\n\n // $FlowFixMe\n return result;\n } else if (isPlainObject(item)) {\n const result = {};\n\n for (const key in item) {\n if (!item.hasOwnProperty(key)) {\n continue;\n }\n\n defineLazyProp(result, key, () => {\n const itemKey = fullKey ? `${ fullKey }.${ key }` : `${ key }`;\n // $FlowFixMe\n const el = item[key];\n\n let child = replacer(el, key, itemKey);\n\n if (isPlainObject(child) || Array.isArray(child)) {\n // $FlowFixMe\n child = replaceObject(child, replacer, itemKey);\n }\n\n return child;\n });\n }\n\n // $FlowFixMe\n return result;\n } else {\n throw new Error(`Pass an object or array`);\n }\n}\n\n\nexport function copyProp(source : Object, target : Object, name : string, def : mixed) {\n if (source.hasOwnProperty(name)) {\n const descriptor = Object.getOwnPropertyDescriptor(source, name);\n // $FlowFixMe\n Object.defineProperty(target, name, descriptor);\n\n } else {\n target[name] = def;\n }\n}\n\ntype RegexResultType = {|\n text : string,\n groups : $ReadOnlyArray,\n start : number,\n end : number,\n length : number,\n replace : (text : string) => string\n|};\n\nexport function regex(pattern : string | RegExp, string : string, start : number = 0) : ?RegexResultType {\n\n if (typeof pattern === 'string') {\n // eslint-disable-next-line security/detect-non-literal-regexp\n pattern = new RegExp(pattern);\n }\n\n const result = string.slice(start).match(pattern);\n\n if (!result) {\n return;\n }\n\n // $FlowFixMe\n const index : number = result.index;\n const regmatch = result[0];\n\n return {\n text: regmatch,\n groups: result.slice(1),\n start: start + index,\n end: start + index + regmatch.length,\n length: regmatch.length,\n\n replace(text : string) : string {\n\n if (!regmatch) {\n return '';\n }\n\n return `${ regmatch.slice(0, start + index) }${ text }${ regmatch.slice(index + regmatch.length) }`;\n }\n };\n}\n\nexport function regexAll(pattern : string | RegExp, string : string) : $ReadOnlyArray {\n\n const matches = [];\n let start = 0;\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const regmatch = regex(pattern, string, start);\n\n if (!regmatch) {\n break;\n }\n\n matches.push(regmatch);\n start = match.end;\n }\n\n return matches;\n}\n\nexport function isDefined(value : ?mixed) : boolean {\n return value !== null && value !== undefined;\n}\n\nexport function cycle(method : Function) : ZalgoPromise {\n return ZalgoPromise.try(method).then(() => cycle(method));\n}\n\nexport function debounce(method : (...args : $ReadOnlyArray) => T, time : number = 100) : (...args : $ReadOnlyArray) => void {\n\n let timeout;\n\n const debounceWrapper = function() {\n clearTimeout(timeout);\n\n timeout = setTimeout(() => {\n return method.apply(this, arguments);\n }, time);\n };\n\n return setFunctionName(debounceWrapper, `${ getFunctionName(method) }::debounced`);\n}\n\nexport function isRegex(item : mixed) : boolean {\n return Object.prototype.toString.call(item) === '[object RegExp]';\n}\n\ntype FunctionProxy = (method : T) => T;\n\n// eslint-disable-next-line flowtype/no-weak-types\nexport const weakMapMemoize : FunctionProxy<*> = (method : (arg : any) => R) : ((...args : $ReadOnlyArray) => R) => {\n\n const weakmap = new WeakMap();\n\n // eslint-disable-next-line flowtype/no-weak-types\n return function weakmapMemoized(arg : any) : R {\n return weakmap.getOrSet(arg, () => method.call(this, arg));\n };\n};\n\ntype FunctionPromiseProxy) => ZalgoPromise> = (T) => T;\n\n// eslint-disable-next-line flowtype/no-weak-types\nexport const weakMapMemoizePromise : FunctionPromiseProxy<*, *> = (method : (arg : any) => ZalgoPromise) : ((...args : $ReadOnlyArray) => ZalgoPromise) => {\n\n const weakmap = new WeakMap();\n\n // eslint-disable-next-line flowtype/no-weak-types\n return function weakmapMemoizedPromise(arg : any) : ZalgoPromise {\n return weakmap.getOrSet(arg, () =>\n method.call(this, arg).finally(() => {\n weakmap.delete(arg);\n }));\n };\n};\n\nexport function getOrSet(obj : O, key : string, getter : () => T) : T {\n if (obj.hasOwnProperty(key)) {\n return obj[key];\n }\n\n const val = getter();\n obj[key] = val;\n return val;\n}\n\nexport type CleanupType = {|\n set : (string, T) => T, // eslint-disable-line no-undef\n register : (Function) => void,\n all : () => ZalgoPromise\n|};\n\nexport function cleanup(obj : Object) : CleanupType {\n\n const tasks = [];\n let cleaned = false;\n\n return {\n set(name : string, item : T) : T {\n if (!cleaned) {\n obj[name] = item;\n this.register(() => {\n delete obj[name];\n });\n }\n return item;\n },\n\n register(method : Function) {\n if (cleaned) {\n method();\n } else {\n tasks.push(once(method));\n }\n },\n\n all() : ZalgoPromise {\n const results = [];\n cleaned = true;\n\n while (tasks.length) {\n const task = tasks.shift();\n results.push(task());\n }\n\n return ZalgoPromise.all(results).then(noop);\n }\n };\n}\n\nexport function tryCatch(fn : () => T) : {| result : T, error : void |} | {| result : void, error : mixed |} {\n let result;\n let error;\n\n try {\n result = fn();\n } catch (err) {\n error = err;\n }\n \n // $FlowFixMe\n return { result, error };\n}\n\n// eslint-disable-next-line flowtype/no-mutable-array\nexport function removeFromArray>(arr : T, item : X) {\n const index = arr.indexOf(item);\n if (index !== -1) {\n arr.splice(index, 1);\n }\n}\n\nexport function assertExists(name : string, thing : void | null | T) : T {\n if (thing === null || typeof thing === 'undefined') {\n throw new Error(`Expected ${ name } to be present`);\n }\n \n return thing;\n}\n\nexport function unique(arr : $ReadOnlyArray) : $ReadOnlyArray {\n const result = {};\n for (const item of arr) {\n result[item] = true;\n }\n return Object.keys(result);\n}\n\nexport const constHas = (constant : T, value : X) : boolean => {\n return memoizedValues(constant).indexOf(value) !== -1;\n};\n\nexport function dedupeErrors(handler : (mixed) => T) : (mixed) => (T | void) {\n const seenErrors = [];\n const seenStringifiedErrors = {};\n\n return (err) => {\n if (seenErrors.indexOf(err) !== -1) {\n return;\n }\n\n seenErrors.push(err);\n\n const stringifiedError = stringifyError(err);\n if (seenStringifiedErrors[stringifiedError]) {\n return;\n }\n\n seenStringifiedErrors[stringifiedError] = true;\n return handler(err);\n };\n}\n\nexport class ExtendableError extends Error {\n constructor(message : string) {\n super(message);\n // eslint-disable-next-line unicorn/custom-error-definition\n this.name = this.constructor.name;\n if (typeof Error.captureStackTrace === 'function') {\n Error.captureStackTrace(this, this.constructor);\n } else {\n this.stack = (new Error(message)).stack;\n }\n }\n}\n \n","/* @flow */\n\nexport function hasNativeWeakMap() : boolean {\n\n if (typeof WeakMap === 'undefined') {\n return false;\n }\n\n if (typeof Object.freeze === 'undefined') {\n return false;\n }\n\n try {\n\n const testWeakMap = new WeakMap();\n const testKey = {};\n const testValue = '__testvalue__';\n\n Object.freeze(testKey);\n\n testWeakMap.set(testKey, testValue);\n\n if (testWeakMap.get(testKey) === testValue) {\n return true;\n }\n\n return false;\n\n } catch (err) {\n\n return false;\n }\n}\n","/* @flow */\n/* eslint max-lines: off */\n\nimport { ZalgoPromise } from 'zalgo-promise/src';\nimport { linkFrameWindow, isWindowClosed,\n type SameDomainWindowType, type CrossDomainWindowType } from 'cross-domain-utils/src';\nimport { WeakMap } from 'cross-domain-safe-weakmap/src';\n\nimport { inlineMemoize, memoize, noop, stringify, capitalizeFirstLetter,\n once, extend, safeInterval, uniqueID, arrayFrom, ExtendableError } from './util';\nimport { isDevice } from './device';\nimport { KEY_CODES, ATTRIBUTES } from './constants';\nimport type { CancelableType } from './types';\n\ntype ElementRefType = string | HTMLElement;\n\nexport function isDocumentReady() : boolean {\n return Boolean(document.body) && (document.readyState === 'complete');\n}\n\nexport function isDocumentInteractive() : boolean {\n return Boolean(document.body) && (document.readyState === 'interactive');\n}\n\nexport function urlEncode(str : string) : string {\n return str.replace(/\\?/g, '%3F').replace(/&/g, '%26').replace(/#/g, '%23').replace(/\\+/g, '%2B');\n}\n\nexport function waitForWindowReady() : ZalgoPromise {\n return inlineMemoize(waitForWindowReady, () : ZalgoPromise => {\n return new ZalgoPromise(resolve => {\n if (isDocumentReady()) {\n resolve();\n }\n\n window.addEventListener('load', () => resolve());\n });\n });\n}\n\ntype WaitForDocumentReady = () => ZalgoPromise;\n\nexport const waitForDocumentReady : WaitForDocumentReady = memoize(() => {\n return new ZalgoPromise(resolve => {\n\n if (isDocumentReady() || isDocumentInteractive()) {\n return resolve();\n }\n\n const interval = setInterval(() => {\n if (isDocumentReady() || isDocumentInteractive()) {\n clearInterval(interval);\n return resolve();\n }\n }, 10);\n });\n});\n\nexport function waitForDocumentBody() : ZalgoPromise {\n return ZalgoPromise.try(() => {\n if (document.body) {\n return document.body;\n }\n\n return waitForDocumentReady().then(() => {\n if (document.body) {\n return document.body;\n }\n\n throw new Error('Document ready but document.body not present');\n });\n });\n}\n\nexport function parseQuery(queryString : string) : Object {\n return inlineMemoize(parseQuery, () : Object => {\n const params = {};\n\n if (!queryString) {\n return params;\n }\n\n if (queryString.indexOf('=') === -1) {\n return params;\n }\n\n for (let pair of queryString.split('&')) {\n pair = pair.split('=');\n\n if (pair[0] && pair[1]) {\n params[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);\n }\n }\n\n return params;\n }, [ queryString ]);\n}\n\n\nexport function getQueryParam(name : string) : string {\n return parseQuery(window.location.search.slice(1))[name];\n}\n\nexport function urlWillRedirectPage(url : string) : boolean {\n\n if (url.indexOf('#') === -1) {\n return true;\n }\n\n if (url.indexOf('#') === 0) {\n return false;\n }\n\n if (url.split('#')[0] === window.location.href.split('#')[0]) {\n return false;\n }\n\n return true;\n}\n\nexport function formatQuery(obj : { [ string ] : string } = {}) : string {\n\n return Object.keys(obj).filter(key => {\n return typeof obj[key] === 'string';\n }).map(key => {\n return `${ urlEncode(key) }=${ urlEncode(obj[key]) }`;\n }).join('&');\n}\n\nexport function extendQuery(originalQuery : string, props : { [ string ] : string } = {}) : string {\n\n if (!props || !Object.keys(props).length) {\n return originalQuery;\n }\n\n return formatQuery({\n ...parseQuery(originalQuery),\n ...props\n });\n}\n\nexport function extendUrl(url : string, options : {| query? : { [string] : string }, hash? : { [string] : string } |}) : string {\n\n const query = options.query || {};\n const hash = options.hash || {};\n\n let originalUrl;\n let originalQuery;\n let originalHash;\n\n [ originalUrl, originalHash ] = url.split('#');\n [ originalUrl, originalQuery ] = originalUrl.split('?');\n\n const queryString = extendQuery(originalQuery, query);\n const hashString = extendQuery(originalHash, hash);\n\n if (queryString) {\n originalUrl = `${ originalUrl }?${ queryString }`;\n }\n\n if (hashString) {\n originalUrl = `${ originalUrl }#${ hashString }`;\n }\n\n return originalUrl;\n}\n\nexport function redirect(url : string, win : CrossDomainWindowType = window) : ZalgoPromise {\n return new ZalgoPromise(resolve => {\n win.location = url;\n if (!urlWillRedirectPage(url)) {\n resolve();\n }\n });\n}\n\nexport function hasMetaViewPort() : boolean {\n const meta = document.querySelector('meta[name=viewport]');\n\n if (isDevice() && window.screen.width < 660 && !meta) {\n return false;\n }\n\n return true;\n}\n\nexport function isElementVisible(el : HTMLElement) : boolean {\n return Boolean(el.offsetWidth || el.offsetHeight || el.getClientRects().length);\n}\n\nexport function getPerformance() : ?Performance {\n return inlineMemoize(getPerformance, () : ?Performance => {\n const performance = window.performance;\n\n if (\n performance &&\n performance.now &&\n performance.timing &&\n performance.timing.connectEnd &&\n performance.timing.navigationStart &&\n (Math.abs(performance.now() - Date.now()) > 1000) &&\n (performance.now() - (performance.timing.connectEnd - performance.timing.navigationStart)) > 0\n ) {\n return performance;\n }\n });\n}\n\nexport function enablePerformance() : boolean {\n return Boolean(getPerformance());\n}\n\nexport function getPageRenderTime() : ZalgoPromise {\n return waitForDocumentReady().then(() => {\n const performance = getPerformance();\n\n if (!performance) {\n return;\n }\n \n const timing = performance.timing;\n\n if (timing.connectEnd && timing.domInteractive) {\n return timing.domInteractive - timing.connectEnd;\n }\n });\n}\n\nexport function htmlEncode(html : string = '') : string {\n return html.toString()\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n .replace(/\\//g, '/');\n}\n\nexport function isBrowser() : boolean {\n return (typeof window !== 'undefined');\n}\n\nexport function querySelectorAll(selector : string, doc : HTMLElement = window.document) : $ReadOnlyArray {\n return Array.prototype.slice.call(doc.querySelectorAll(selector));\n}\n\nexport function onClick(element : HTMLElement, handler : (Event) => void) {\n element.addEventListener('touchstart', noop);\n element.addEventListener('click', handler);\n element.addEventListener('keypress', (event : Event) => {\n // $FlowFixMe\n if (event.keyCode === KEY_CODES.ENTER || event.keyCode === KEY_CODES.SPACE) { // eslint-disable-line unicorn/prefer-event-key\n return handler(event);\n }\n });\n}\n\nexport function getScript({ host = window.location.host, path, reverse = false } : {| host? : string, path : string, reverse? : boolean |}) : ?HTMLScriptElement {\n return inlineMemoize(getScript, () : ?HTMLScriptElement => {\n\n const url = `${ host }${ path }`;\n const scripts = Array.prototype.slice.call(document.getElementsByTagName('script'));\n\n if (reverse) {\n scripts.reverse();\n }\n\n for (const script of scripts) {\n if (!script.src) {\n continue;\n }\n\n const src = script.src.replace(/^https?:\\/\\//, '').split('?')[0];\n\n if (src === url) {\n return script;\n }\n }\n }, [ path ]);\n}\n\nexport function isLocalStorageEnabled() : boolean {\n return inlineMemoize(isLocalStorageEnabled, () => {\n try {\n if (typeof window === 'undefined') {\n return false;\n }\n\n if (window.localStorage) {\n const value = Math.random().toString();\n window.localStorage.setItem('__test__localStorage__', value);\n const result = window.localStorage.getItem('__test__localStorage__');\n window.localStorage.removeItem('__test__localStorage__');\n if (value === result) {\n return true;\n }\n }\n } catch (err) {\n // pass\n }\n return false;\n });\n}\n\nexport function getBrowserLocales() : $ReadOnlyArray<{| country? : string, lang : string |}> {\n const nav = window.navigator; // eslint-disable-line compat/compat\n\n const locales = nav.languages\n ? [ ...nav.languages ]\n : [];\n\n if (nav.language) {\n locales.push(nav.language);\n }\n\n if (nav.userLanguage) {\n locales.push(nav.userLanguage);\n }\n\n return locales.map(locale => {\n\n if (locale && locale.match(/^[a-z]{2}[-_][A-Z]{2}$/)) {\n const [ lang, country ] = locale.split(/[-_]/);\n return { country, lang };\n }\n\n if (locale && locale.match(/^[a-z]{2}$/)) {\n return { lang: locale };\n }\n\n return null;\n\n }).filter(Boolean);\n}\n\n\nexport function appendChild(container : HTMLElement, child : HTMLElement | Text) {\n container.appendChild(child);\n}\n\nexport function isElement(element : mixed) : boolean {\n\n if (element instanceof window.Element) {\n return true;\n }\n\n if (element !== null && typeof element === 'object' && element.nodeType === 1 && typeof element.style === 'object' && typeof element.ownerDocument === 'object') {\n return true;\n }\n\n return false;\n}\n\nexport function getElementSafe(id : ElementRefType, doc : Document | HTMLElement = document) : ?HTMLElement {\n\n if (isElement(id)) {\n // $FlowFixMe\n return id;\n }\n\n if (typeof id === 'string') {\n return doc.querySelector(id);\n }\n}\n\nexport function getElement(id : ElementRefType, doc : Document | HTMLElement = document) : HTMLElement {\n\n const element = getElementSafe(id, doc);\n\n if (element) {\n return element;\n }\n\n throw new Error(`Can not find element: ${ stringify(id) }`);\n}\n\nexport function elementReady(id : ElementRefType) : ZalgoPromise {\n return new ZalgoPromise((resolve, reject) => {\n\n const name = stringify(id);\n let el = getElementSafe(id);\n\n if (el) {\n return resolve(el);\n }\n\n if (isDocumentReady()) {\n return reject(new Error(`Document is ready and element ${ name } does not exist`));\n }\n\n const interval = setInterval(() => {\n\n el = getElementSafe(id);\n\n if (el) {\n clearInterval(interval);\n return resolve(el);\n }\n\n if (isDocumentReady()) {\n clearInterval(interval);\n return reject(new Error(`Document is ready and element ${ name } does not exist`));\n }\n }, 10);\n });\n}\n\n// eslint-disable-next-line unicorn/custom-error-definition\nexport class PopupOpenError extends ExtendableError {}\n\ntype PopupOptions = {|\n name? : string,\n width? : number,\n height? : number,\n top? : number,\n left? : number,\n status? : 0 | 1,\n resizable? : 0 | 1,\n toolbar? : 0 | 1,\n menubar? : 0 | 1,\n scrollbars? : 0 | 1\n|};\n\nexport function popup(url : string, options? : PopupOptions) : CrossDomainWindowType {\n\n // $FlowFixMe\n options = options || {};\n\n const { width, height } = options;\n\n let top = 0;\n let left = 0;\n\n if (width) {\n if (window.outerWidth) {\n left = Math.round((window.outerWidth - width) / 2) + window.screenX;\n } else if (window.screen.width) {\n left = Math.round((window.screen.width - width) / 2);\n }\n }\n\n if (height) {\n if (window.outerHeight) {\n top = Math.round((window.outerHeight - height) / 2) + window.screenY;\n } else if (window.screen.height) {\n top = Math.round((window.screen.height - height) / 2);\n }\n }\n\n if (width && height) {\n // $FlowFixMe\n options = {\n top,\n left,\n width,\n height,\n status: 1,\n toolbar: 0,\n menubar: 0,\n resizable: 1,\n scrollbars: 1,\n ...options\n };\n }\n\n const name = options.name || '';\n delete options.name;\n\n // eslint-disable-next-line array-callback-return\n const params = Object.keys(options).map(key => {\n // $FlowFixMe\n if (options[key] !== null && options[key] !== undefined) {\n return `${ key }=${ stringify(options[key]) }`;\n }\n }).filter(Boolean).join(',');\n\n let win;\n\n try {\n win = window.open(url, name, params, true);\n } catch (err) {\n throw new PopupOpenError(`Can not open popup window - ${ err.stack || err.message }`);\n }\n\n if (isWindowClosed(win)) {\n const err = new PopupOpenError(`Can not open popup window - blocked`);\n throw err;\n }\n\n window.addEventListener('unload', () => win.close());\n\n return win;\n}\n\n\nexport function writeToWindow(win : SameDomainWindowType, html : string) {\n try {\n win.document.open();\n win.document.write(html);\n win.document.close();\n } catch (err) {\n try {\n win.location = `javascript: document.open(); document.write(${ JSON.stringify(html) }); document.close();`;\n } catch (err2) {\n // pass\n }\n }\n}\n\nexport function writeElementToWindow(win : SameDomainWindowType, el : HTMLElement) {\n\n const tag = el.tagName.toLowerCase();\n\n if (tag !== 'html') {\n throw new Error(`Expected element to be html, got ${ tag }`);\n }\n\n const documentElement = win.document.documentElement;\n\n for (const child of arrayFrom(documentElement.children)) {\n documentElement.removeChild(child);\n }\n\n for (const child of arrayFrom(el.children)) {\n documentElement.appendChild(child);\n }\n}\n\nexport function setStyle(el : HTMLElement, styleText : string, doc : Document = window.document) {\n // $FlowFixMe\n if (el.styleSheet) {\n // $FlowFixMe\n el.styleSheet.cssText = styleText;\n } else {\n el.appendChild(doc.createTextNode(styleText));\n }\n}\n\nexport type ElementOptionsType = {|\n style? : { [ string ] : string },\n id? : string,\n class? : ?$ReadOnlyArray,\n attributes? : { [ string ] : string },\n styleSheet? : ?string,\n html? : ?string\n|};\n\nlet awaitFrameLoadPromises : WeakMap>;\n\nexport function awaitFrameLoad(frame : HTMLIFrameElement) : ZalgoPromise {\n awaitFrameLoadPromises = awaitFrameLoadPromises || new WeakMap();\n\n if (awaitFrameLoadPromises.has(frame)) {\n const promise = awaitFrameLoadPromises.get(frame);\n if (promise) {\n return promise;\n }\n }\n\n const promise = new ZalgoPromise((resolve, reject) => {\n frame.addEventListener('load', () => {\n linkFrameWindow(frame);\n resolve(frame);\n });\n\n frame.addEventListener('error', (err : Event) => {\n if (frame.contentWindow) {\n resolve(frame);\n } else {\n reject(err);\n }\n });\n });\n\n awaitFrameLoadPromises.set(frame, promise);\n\n return promise;\n}\n\nexport function awaitFrameWindow(frame : HTMLIFrameElement) : ZalgoPromise {\n return awaitFrameLoad(frame).then(loadedFrame => {\n\n if (!loadedFrame.contentWindow) {\n throw new Error(`Could not find window in iframe`);\n }\n\n return loadedFrame.contentWindow;\n });\n}\n\nconst getDefaultCreateElementOptions = () : ElementOptionsType => {\n // $FlowFixMe\n return {};\n};\n\nexport function createElement(tag : string = 'div', options : ElementOptionsType = getDefaultCreateElementOptions(), container : ?HTMLElement) : HTMLElement {\n\n tag = tag.toLowerCase();\n const element = document.createElement(tag);\n\n if (options.style) {\n extend(element.style, options.style);\n }\n\n if (options.class) {\n element.className = options.class.join(' ');\n }\n\n if (options.id) {\n element.setAttribute('id', options.id);\n }\n\n if (options.attributes) {\n for (const key of Object.keys(options.attributes)) {\n element.setAttribute(key, options.attributes[key]);\n }\n }\n\n if (options.styleSheet) {\n setStyle(element, options.styleSheet);\n }\n\n if (container) {\n appendChild(container, element);\n }\n\n if (options.html) {\n if (tag === 'iframe') {\n // $FlowFixMe\n if (!container || !element.contentWindow) {\n throw new Error(`Iframe html can not be written unless container provided and iframe in DOM`);\n }\n\n // $FlowFixMe\n writeToWindow(element.contentWindow, options.html);\n\n } else {\n element.innerHTML = options.html;\n }\n }\n\n return element;\n}\n\ntype StringMap = {|\n [ string ] : string\n|};\n\nexport type IframeElementOptionsType = {|\n style? : StringMap,\n class? : ?$ReadOnlyArray,\n attributes? : StringMap,\n styleSheet? : ?string,\n html? : ?string,\n url? : ?string\n|};\n\nconst getDefaultIframeOptions = () : IframeElementOptionsType => {\n // $FlowFixMe\n return {};\n};\n\nconst getDefaultStringMap = () : StringMap => {\n // $FlowFixMe\n return {};\n};\n\nexport function iframe(options : IframeElementOptionsType = getDefaultIframeOptions(), container : ?HTMLElement) : HTMLIFrameElement {\n\n const attributes = options.attributes || getDefaultStringMap();\n const style = options.style || getDefaultStringMap();\n\n // $FlowFixMe\n const newAttributes = {\n allowTransparency: 'true',\n ...attributes\n };\n\n // $FlowFixMe\n const newStyle = {\n backgroundColor: 'transparent',\n border: 'none',\n ...style\n };\n\n const frame = createElement('iframe', {\n attributes: newAttributes,\n style: newStyle,\n html: options.html,\n class: options.class\n });\n\n const isIE = window.navigator.userAgent.match(/MSIE|Edge/i); // eslint-disable-line compat/compat\n\n if (!frame.hasAttribute('id')) {\n frame.setAttribute('id', uniqueID());\n }\n\n // $FlowFixMe\n awaitFrameLoad(frame);\n\n if (container) {\n const el = getElement(container);\n el.appendChild(frame);\n }\n\n if (options.url || isIE) {\n frame.setAttribute('src', options.url || 'about:blank');\n }\n\n // $FlowFixMe\n return frame;\n}\n\nexport function addEventListener(obj : HTMLElement, event : string, handler : (event : Event) => void) : CancelableType {\n obj.addEventListener(event, handler);\n return {\n cancel() {\n obj.removeEventListener(event, handler);\n }\n };\n}\n\nexport function bindEvents(element : HTMLElement, eventNames : $ReadOnlyArray, handler : (event : Event) => void) : CancelableType {\n\n handler = once(handler);\n\n for (const eventName of eventNames) {\n element.addEventListener(eventName, handler);\n }\n\n return {\n cancel: once(() => {\n for (const eventName of eventNames) {\n element.removeEventListener(eventName, handler);\n }\n })\n };\n}\n\nconst VENDOR_PREFIXES = [ 'webkit', 'moz', 'ms', 'o' ];\n\nexport function setVendorCSS(element : HTMLElement, name : string, value : string) {\n\n // $FlowFixMe\n element.style[name] = value;\n\n const capitalizedName = capitalizeFirstLetter(name);\n\n for (const prefix of VENDOR_PREFIXES) {\n // $FlowFixMe\n element.style[`${ prefix }${ capitalizedName }`] = value;\n }\n}\n\nconst ANIMATION_START_EVENTS = [ 'animationstart', 'webkitAnimationStart', 'oAnimationStart', 'MSAnimationStart' ];\nconst ANIMATION_END_EVENTS = [ 'animationend', 'webkitAnimationEnd', 'oAnimationEnd', 'MSAnimationEnd' ];\n\nexport function animate(element : ElementRefType, name : string, clean : (Function) => void, timeout : number = 1000) : ZalgoPromise {\n return new ZalgoPromise((resolve, reject) => {\n\n const el = getElement(element);\n\n if (!el) {\n return resolve();\n }\n\n let hasStarted = false;\n\n // eslint-disable-next-line prefer-const\n let startTimeout;\n let endTimeout;\n // eslint-disable-next-line prefer-const\n let startEvent;\n // eslint-disable-next-line prefer-const\n let endEvent;\n\n function cleanUp() {\n clearTimeout(startTimeout);\n clearTimeout(endTimeout);\n startEvent.cancel();\n endEvent.cancel();\n }\n\n startEvent = bindEvents(el, ANIMATION_START_EVENTS, event => {\n\n // $FlowFixMe\n if (event.target !== el || event.animationName !== name) {\n return;\n }\n\n clearTimeout(startTimeout);\n\n event.stopPropagation();\n\n startEvent.cancel();\n hasStarted = true;\n\n endTimeout = setTimeout(() => {\n cleanUp();\n resolve();\n }, timeout);\n });\n\n endEvent = bindEvents(el, ANIMATION_END_EVENTS, event => {\n\n // $FlowFixMe\n if (event.target !== el || event.animationName !== name) {\n return;\n }\n\n cleanUp();\n\n // $FlowFixMe\n if (typeof event.animationName === 'string' && event.animationName !== name) {\n return reject(`Expected animation name to be ${ name }, found ${ event.animationName }`);\n }\n\n return resolve();\n });\n\n setVendorCSS(el, 'animationName', name);\n\n startTimeout = setTimeout(() => {\n if (!hasStarted) {\n cleanUp();\n return resolve();\n }\n }, 200);\n\n if (clean) {\n clean(cleanUp);\n }\n });\n}\n\nexport function makeElementVisible(element : HTMLElement) {\n element.style.setProperty('visibility', '');\n}\n\nexport function makeElementInvisible(element : HTMLElement) {\n element.style.setProperty('visibility', 'hidden', 'important');\n}\n\n\nexport function showElement(element : HTMLElement) {\n element.style.setProperty('display', '');\n}\n\nexport function hideElement(element : HTMLElement) {\n element.style.setProperty('display', 'none', 'important');\n}\n\nexport function destroyElement(element : HTMLElement) {\n if (element && element.parentNode) {\n element.parentNode.removeChild(element);\n }\n}\n\nexport function showAndAnimate(element : HTMLElement, name : string, clean : (Function) => void) : ZalgoPromise {\n const animation = animate(element, name, clean);\n showElement(element);\n return animation;\n}\n\nexport function animateAndHide(element : HTMLElement, name : string, clean : (Function) => void) : ZalgoPromise {\n return animate(element, name, clean).then(() => {\n hideElement(element);\n });\n}\n\nexport function addClass(element : HTMLElement, name : string) {\n element.classList.add(name);\n}\n\nexport function removeClass(element : HTMLElement, name : string) {\n element.classList.remove(name);\n}\n\nexport function isElementClosed(el : HTMLElement) : boolean {\n if (!el || !el.parentNode) {\n return true;\n }\n return false;\n}\n\nexport function watchElementForClose(element : HTMLElement, handler : () => mixed) : CancelableType {\n handler = once(handler);\n\n let interval;\n\n if (isElementClosed(element)) {\n handler();\n } else {\n interval = safeInterval(() => {\n if (isElementClosed(element)) {\n interval.cancel();\n handler();\n }\n }, 50);\n }\n\n return {\n cancel() {\n if (interval) {\n interval.cancel();\n }\n }\n };\n}\n\nexport function fixScripts(el : HTMLElement, doc : Document = window.document) {\n for (const script of querySelectorAll('script', el)) {\n const parentNode = script.parentNode;\n\n if (!parentNode) {\n continue;\n }\n\n const newScript = doc.createElement('script');\n newScript.text = script.textContent;\n parentNode.replaceChild(newScript, script);\n }\n}\n\ntype OnResizeOptions = {|\n width? : boolean,\n height? : boolean,\n interval? : number,\n win? : SameDomainWindowType\n|};\n\nexport function onResize(el : HTMLElement, handler : ({| width : number, height : number |}) => void, { width = true, height = true, interval = 100, win = window } : OnResizeOptions = {}) : {| cancel : () => void |} {\n let currentWidth = el.offsetWidth;\n let currentHeight = el.offsetHeight;\n let canceled = false;\n\n handler({ width: currentWidth, height: currentHeight });\n\n const check = () => {\n if (canceled || !isElementVisible(el)) {\n return;\n }\n\n const newWidth = el.offsetWidth;\n const newHeight = el.offsetHeight;\n\n if ((width && newWidth !== currentWidth) || (height && newHeight !== currentHeight)) {\n handler({ width: newWidth, height: newHeight });\n }\n\n currentWidth = newWidth;\n currentHeight = newHeight;\n };\n\n let observer;\n let timeout;\n\n win.addEventListener('resize', check);\n \n if (typeof win.ResizeObserver !== 'undefined') {\n observer = new win.ResizeObserver(check);\n observer.observe(el);\n timeout = safeInterval(check, interval * 10);\n\n } else if (typeof win.MutationObserver !== 'undefined') {\n observer = new win.MutationObserver(check);\n observer.observe(el, {\n attributes: true,\n childList: true,\n subtree: true,\n characterData: false\n });\n timeout = safeInterval(check, interval * 10);\n } else {\n timeout = safeInterval(check, interval);\n }\n\n return {\n cancel: () => {\n canceled = true;\n observer.disconnect();\n window.removeEventListener('resize', check);\n timeout.cancel();\n }\n };\n}\n\nexport function getResourceLoadTime(url : string) : ?number {\n const performance = getPerformance();\n\n if (!performance) {\n return;\n }\n\n if (typeof performance.getEntries !== 'function') {\n return;\n }\n\n const entries = performance.getEntries();\n\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n\n if (entry && entry.name && entry.name.indexOf(url) === 0 && typeof entry.duration === 'number') {\n return Math.floor(entry.duration);\n }\n }\n}\n\nexport function isShadowElement(element : Node) : boolean {\n while (element.parentNode) {\n element = element.parentNode;\n }\n\n return element.toString() === '[object ShadowRoot]';\n}\n\nexport function getShadowRoot(element : Node) : ?Node {\n while (element.parentNode) {\n element = element.parentNode;\n }\n\n if (isShadowElement(element)) {\n return element;\n }\n}\n\nexport function getShadowHost(element : Node) : ?HTMLElement {\n const shadowRoot = getShadowRoot(element);\n\n // $FlowFixMe\n if (shadowRoot.host) {\n // $FlowFixMe\n return shadowRoot.host;\n }\n}\n\nexport function insertShadowSlot(element : HTMLElement) : HTMLElement {\n const shadowHost = getShadowHost(element);\n\n if (!shadowHost) {\n throw new Error(`Element is not in shadow dom`);\n }\n\n if (isShadowElement(shadowHost)) {\n throw new Error(`Host element is also in shadow dom`);\n }\n\n const slotName = `shadow-slot-${ uniqueID() }`;\n\n const slot = document.createElement('slot');\n slot.setAttribute('name', slotName);\n element.appendChild(slot);\n \n const slotProvider = document.createElement('div');\n slotProvider.setAttribute('slot', slotName);\n shadowHost.appendChild(slotProvider);\n\n return slotProvider;\n}\n\nexport function preventClickFocus(el : HTMLElement) {\n const onFocus = (event : Event) => {\n el.removeEventListener('focus', onFocus);\n event.preventDefault();\n el.blur();\n return false;\n };\n\n el.addEventListener('mousedown', () => {\n el.addEventListener('focus', onFocus);\n setTimeout(() => {\n el.removeEventListener('focus', onFocus);\n }, 1);\n });\n}\n\nexport function getStackTrace() : string {\n try {\n throw new Error('_');\n }\n catch (err) {\n return err.stack || '';\n }\n}\n\nfunction inferCurrentScript() : ?HTMLScriptElement {\n try {\n const stack = getStackTrace();\n const stackDetails = (/.*at [^(]*\\((.*):(.+):(.+)\\)$/ig).exec(stack);\n const scriptLocation = stackDetails && stackDetails[1];\n\n if (!scriptLocation) {\n return;\n }\n\n for (const script of Array.prototype.slice.call(document.getElementsByTagName('script')).reverse()) {\n if (script.src && script.src === scriptLocation) {\n return script;\n }\n }\n\n } catch (err) {\n // pass\n }\n}\n\n// eslint-disable-next-line compat/compat\nlet currentScript = typeof document !== 'undefined' ? document.currentScript : null;\n\ntype GetCurrentScript = () => HTMLScriptElement;\n\nexport const getCurrentScript : GetCurrentScript = memoize(() => {\n if (currentScript) {\n return currentScript;\n }\n\n currentScript = inferCurrentScript();\n\n if (currentScript) {\n return currentScript;\n }\n\n throw new Error('Can not determine current script');\n});\n\nconst currentUID = uniqueID();\n\ntype GetCurrentScriptUID = () => string;\n\nexport const getCurrentScriptUID : GetCurrentScriptUID = memoize(() => {\n let script;\n\n try {\n script = getCurrentScript();\n } catch (err) {\n return currentUID;\n }\n\n let uid = script.getAttribute(ATTRIBUTES.UID);\n\n if (uid && typeof uid === 'string') {\n return uid;\n }\n\n uid = uniqueID();\n script.setAttribute(ATTRIBUTES.UID, uid);\n\n return uid;\n});\n","/* @flow */\n\nexport const KEY_CODES = {\n ENTER: 13,\n SPACE: 32\n};\n\nexport const ATTRIBUTES = {\n UID: 'data-uid'\n};\n","/* @flow */\n\nimport { ZalgoPromise } from 'zalgo-promise/src';\nimport { type SameDomainWindowType } from 'cross-domain-utils/src';\n\ntype RequestOptionsType = {|\n url : string,\n method? : string,\n headers? : { [key : string] : string },\n json? : $ReadOnlyArray | Object,\n data? : { [key : string] : string },\n body? : string,\n win? : SameDomainWindowType,\n timeout? : number\n|};\n\ntype ResponseType = {|\n status : number,\n headers : { [string] : string },\n body : Object\n|};\n\nconst HEADERS = {\n CONTENT_TYPE: 'content-type',\n ACCEPT: 'accept'\n};\n\nconst headerBuilders = [];\n\nfunction parseHeaders(rawHeaders : string = '') : { [string] : string } {\n const result = {};\n for (const line of rawHeaders.trim().split('\\n')) {\n const [ key, ...values ] = line.split(':');\n result[key.toLowerCase()] = values.join(':').trim();\n }\n return result;\n}\n\nexport function request({ url, method = 'get', headers = {}, json, data, body, win = window, timeout = 0 } : RequestOptionsType) : ZalgoPromise {\n return new ZalgoPromise((resolve, reject) => {\n\n if ((json && data) || (json && body) || (data && json)) {\n throw new Error(`Only options.json or options.data or options.body should be passed`);\n }\n\n const normalizedHeaders = {};\n\n for (const key of Object.keys(headers)) {\n normalizedHeaders[key.toLowerCase()] = headers[key];\n }\n\n if (json) {\n normalizedHeaders[HEADERS.CONTENT_TYPE] = normalizedHeaders[HEADERS.CONTENT_TYPE] || 'application/json';\n } else if (data || body) {\n normalizedHeaders[HEADERS.CONTENT_TYPE] = normalizedHeaders[HEADERS.CONTENT_TYPE] || 'application/x-www-form-urlencoded; charset=utf-8';\n }\n\n normalizedHeaders[HEADERS.ACCEPT] = normalizedHeaders[HEADERS.ACCEPT] || 'application/json';\n\n for (const headerBuilder of headerBuilders) {\n const builtHeaders = headerBuilder();\n\n for (const key of Object.keys(builtHeaders)) {\n normalizedHeaders[key.toLowerCase()] = builtHeaders[key];\n }\n }\n\n const xhr = new win.XMLHttpRequest();\n\n xhr.addEventListener('load', function xhrLoad() : void {\n\n const responseHeaders = parseHeaders(this.getAllResponseHeaders());\n\n if (!this.status) {\n return reject(new Error(`Request to ${ method.toLowerCase() } ${ url } failed: no response status code.`));\n }\n \n const contentType = responseHeaders['content-type'];\n const isJSON = contentType && (contentType.indexOf('application/json') === 0 || contentType.indexOf('text/json') === 0);\n let responseBody = this.responseText;\n\n try {\n responseBody = JSON.parse(responseBody);\n } catch (err) {\n if (isJSON) {\n return reject(new Error(`Invalid json: ${ this.responseText }.`));\n }\n }\n\n const res = {\n status: this.status,\n headers: responseHeaders,\n body: responseBody\n };\n\n return resolve(res);\n\n }, false);\n\n xhr.addEventListener('error', (evt) => {\n reject(new Error(`Request to ${ method.toLowerCase() } ${ url } failed: ${ evt.toString() }.`));\n }, false);\n\n xhr.open(method, url, true);\n\n for (const key in normalizedHeaders) {\n if (normalizedHeaders.hasOwnProperty(key)) {\n xhr.setRequestHeader(key, normalizedHeaders[key]);\n }\n }\n\n if (json) {\n body = JSON.stringify(json);\n } else if (data) {\n body = Object.keys(data).map(key => {\n return `${ encodeURIComponent(key) }=${ data ? encodeURIComponent(data[key]) : '' }`;\n }).join('&');\n }\n\n xhr.timeout = timeout;\n xhr.ontimeout = function xhrTimeout() {\n reject(new Error(`Request to ${ method.toLowerCase() } ${ url } has timed out`));\n };\n\n xhr.send(body);\n });\n}\n\nexport function addHeaderBuilder(method : () => { [string] : string }) {\n headerBuilders.push(method);\n}\n","/* @flow */\n\nexport const LOG_LEVEL = {\n DEBUG: ('debug' : 'debug'),\n INFO: ('info' : 'info'),\n WARN: ('warn' : 'warn'),\n ERROR: ('error' : 'error')\n};\n\nexport const PROTOCOL = {\n FILE: 'file:'\n};\n","/* @flow */\n\nimport { LOG_LEVEL } from './constants';\n\nexport const AUTO_FLUSH_LEVEL = [ LOG_LEVEL.WARN, LOG_LEVEL.ERROR ];\n\nexport const LOG_LEVEL_PRIORITY = [ LOG_LEVEL.ERROR, LOG_LEVEL.WARN, LOG_LEVEL.INFO, LOG_LEVEL.DEBUG ];\n\nexport const FLUSH_INTERVAL = 60 * 1000;\n\nexport const DEFAULT_LOG_LEVEL : $Values = __DEBUG__ ? LOG_LEVEL.DEBUG : LOG_LEVEL.WARN;\n","/* @flow */\n\nimport { ZalgoPromise } from 'zalgo-promise/src';\nimport { request, isBrowser, promiseDebounce, noop, safeInterval, objFilter } from 'belter/src';\n\nimport { DEFAULT_LOG_LEVEL, LOG_LEVEL_PRIORITY, AUTO_FLUSH_LEVEL, FLUSH_INTERVAL } from './config';\nimport { LOG_LEVEL, PROTOCOL } from './constants';\n\ntype TransportOptions = {|\n url : string,\n method : string,\n headers : { [string] : string },\n json : Object,\n enableSendBeacon : boolean\n|};\n\ntype Payload = { [string] : string | boolean };\ntype Transport = (TransportOptions) => ZalgoPromise;\n\ntype LoggerOptions = {|\n url : string,\n prefix? : string,\n logLevel? : $Values,\n transport? : Transport,\n flushInterval? : number,\n enableSendBeacon? : boolean,\n enableBrowserLogging? : boolean\n|};\n\ntype ClientPayload = { [string] : ?string | ?boolean };\ntype Log = (name : string, payload? : ClientPayload) => LoggerType; // eslint-disable-line no-use-before-define\ntype Track = (payload : ClientPayload) => LoggerType; // eslint-disable-line no-use-before-define\n\ntype Builder = (Payload) => ClientPayload;\ntype AddBuilder = (Builder) => LoggerType; // eslint-disable-line no-use-before-define\n\nexport type LoggerType = {|\n debug : Log,\n info : Log,\n warn : Log,\n error : Log,\n\n track : Track,\n\n flush : () => ZalgoPromise,\n immediateFlush : () => ZalgoPromise,\n\n addPayloadBuilder : AddBuilder,\n addMetaBuilder : AddBuilder,\n addTrackingBuilder : AddBuilder,\n addHeaderBuilder : AddBuilder,\n\n setTransport : (Transport) => LoggerType\n|};\n\nfunction httpTransport({ url, method, headers, json, enableSendBeacon = false } : TransportOptions) : ZalgoPromise {\n const hasHeaders = headers && Object.keys(headers).length;\n if (window && window.navigator.sendBeacon && !hasHeaders && enableSendBeacon && window.Blob) {\n return new ZalgoPromise(resolve => {\n const blob = new Blob([ JSON.stringify(json) ], { type: 'application/json' });\n resolve(window.navigator.sendBeacon(url, blob));\n });\n } else {\n return request({ url, method, headers, json }).then(noop);\n }\n}\n\nfunction extendIfDefined(target : { [string] : string | boolean }, source : { [string] : ?string | ?boolean }) {\n for (const key in source) {\n if (source.hasOwnProperty(key) && source[key] && !target[key]) {\n target[key] = source[key];\n }\n }\n}\n\nexport function Logger({ url, prefix, logLevel = DEFAULT_LOG_LEVEL, transport = httpTransport, flushInterval = FLUSH_INTERVAL, enableSendBeacon = false, enableBrowserLogging = true } : LoggerOptions) : LoggerType {\n\n let events : Array<{| level : $Values, event : string, payload : Payload |}> = [];\n let tracking : Array = [];\n\n const payloadBuilders : Array = [];\n const metaBuilders : Array = [];\n const trackingBuilders : Array = [];\n const headerBuilders : Array = [];\n\n function print(level : $Values, event : string, payload : Payload) {\n\n if (!isBrowser() || !window.console || !window.console.log || !enableBrowserLogging) {\n return;\n }\n\n if (LOG_LEVEL_PRIORITY.indexOf(level) > LOG_LEVEL_PRIORITY.indexOf(logLevel)) {\n return;\n }\n\n const args = [ event ];\n\n args.push(payload);\n\n if (payload.error || payload.warning) {\n args.push('\\n\\n', payload.error || payload.warning);\n }\n\n try {\n if (window.console[level] && window.console[level].apply) {\n window.console[level].apply(window.console, args);\n } else if (window.console.log && window.console.log.apply) {\n window.console.log.apply(window.console, args);\n }\n } catch (err) {\n // pass\n }\n }\n\n function immediateFlush() : ZalgoPromise {\n return ZalgoPromise.try(() => {\n if (!isBrowser() || window.location.protocol === PROTOCOL.FILE) {\n return;\n }\n\n if (!events.length && !tracking.length) {\n return;\n }\n\n const meta = {};\n for (const builder of metaBuilders) {\n extendIfDefined(meta, builder(meta));\n }\n\n const headers = {};\n for (const builder of headerBuilders) {\n extendIfDefined(headers, builder(headers));\n }\n\n const res = transport({\n method: 'POST',\n url,\n headers,\n json: {\n events,\n meta,\n tracking\n },\n enableSendBeacon\n });\n\n events = [];\n tracking = [];\n\n return res.then(noop);\n });\n }\n\n const flush = promiseDebounce(immediateFlush);\n\n function enqueue(level : $Values, event : string, payload : Payload) {\n\n events.push({\n level,\n event,\n payload\n });\n\n if (AUTO_FLUSH_LEVEL.indexOf(level) !== -1) {\n flush();\n }\n }\n\n function log(level : $Values, event : string, payload = {}) : LoggerType {\n\n if (!isBrowser()) {\n return logger; // eslint-disable-line no-use-before-define\n }\n\n if (prefix) {\n event = `${ prefix }_${ event }`;\n }\n\n const logPayload : Payload = {\n ...objFilter(payload),\n timestamp: Date.now().toString()\n };\n\n for (const builder of payloadBuilders) {\n extendIfDefined(logPayload, builder(logPayload));\n }\n\n enqueue(level, event, logPayload);\n print(level, event, logPayload);\n\n return logger; // eslint-disable-line no-use-before-define\n }\n\n function addBuilder(builders, builder) : LoggerType {\n builders.push(builder);\n return logger; // eslint-disable-line no-use-before-define\n }\n\n function addPayloadBuilder(builder) : LoggerType {\n return addBuilder(payloadBuilders, builder);\n }\n\n function addMetaBuilder(builder) : LoggerType {\n return addBuilder(metaBuilders, builder);\n }\n\n function addTrackingBuilder(builder) : LoggerType {\n return addBuilder(trackingBuilders, builder);\n }\n\n function addHeaderBuilder(builder) : LoggerType {\n return addBuilder(headerBuilders, builder);\n }\n\n function debug(event, payload) : LoggerType {\n return log(LOG_LEVEL.DEBUG, event, payload);\n }\n\n function info(event, payload) : LoggerType {\n return log(LOG_LEVEL.INFO, event, payload);\n }\n\n function warn(event, payload) : LoggerType {\n return log(LOG_LEVEL.WARN, event, payload);\n }\n\n function error(event, payload) : LoggerType {\n return log(LOG_LEVEL.ERROR, event, payload);\n }\n\n function track(payload = {}) : LoggerType {\n if (!isBrowser()) {\n return logger; // eslint-disable-line no-use-before-define\n }\n\n const trackingPayload : Payload = objFilter(payload);\n\n for (const builder of trackingBuilders) {\n extendIfDefined(trackingPayload, builder(trackingPayload));\n }\n\n print(LOG_LEVEL.DEBUG, 'track', trackingPayload);\n tracking.push(trackingPayload);\n\n return logger; // eslint-disable-line no-use-before-define\n }\n\n function setTransport(newTransport : Transport) : LoggerType {\n transport = newTransport;\n return logger; // eslint-disable-line no-use-before-define\n }\n\n if (isBrowser()) {\n safeInterval(flush, flushInterval);\n }\n\n if (typeof window === 'object') {\n window.addEventListener('beforeunload', () => {\n immediateFlush();\n });\n\n window.addEventListener('unload', () => {\n immediateFlush();\n });\n }\n\n const logger = {\n debug,\n info,\n warn,\n error,\n track,\n flush,\n immediateFlush,\n addPayloadBuilder,\n addMetaBuilder,\n addTrackingBuilder,\n addHeaderBuilder,\n setTransport\n };\n\n return logger;\n}\n"],"sourceRoot":""} \ No newline at end of file +{"version":3,"sources":["webpack://beaver/webpack/universalModuleDefinition","webpack://beaver/webpack/bootstrap","webpack://beaver/./node_modules/@babel/runtime/helpers/esm/extends.js","webpack://beaver/./node_modules/zalgo-promise/src/utils.js","webpack://beaver/./node_modules/zalgo-promise/src/exceptions.js","webpack://beaver/./node_modules/zalgo-promise/src/flush.js","webpack://beaver/./node_modules/zalgo-promise/src/promise.js","webpack://beaver/./node_modules/cross-domain-utils/src/utils.js","webpack://beaver/./node_modules/cross-domain-utils/src/constants.js","webpack://beaver/./node_modules/cross-domain-safe-weakmap/src/util.js","webpack://beaver/./node_modules/cross-domain-safe-weakmap/src/weakmap.js","webpack://beaver/./node_modules/belter/src/util.js","webpack://beaver/./node_modules/cross-domain-safe-weakmap/src/native.js","webpack://beaver/./node_modules/belter/src/dom.js","webpack://beaver/./node_modules/belter/src/constants.js","webpack://beaver/./node_modules/belter/src/http.js","webpack://beaver/./src/constants.js","webpack://beaver/./src/config.js","webpack://beaver/./src/logger.js"],"names":["root","factory","exports","module","define","amd","self","this","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","hasOwnProperty","p","s","_extends","assign","target","arguments","length","source","apply","isPromise","item","Promise","window","Window","constructor","toString","then","err","flushPromise","dispatchedErrors","possiblyUnhandledPromiseHandlers","activeCount","flushActive","promise","resolve","startActive","endActive","ZalgoPromise","handler","resolved","rejected","errorHandled","error","handlers","dispatching","stack","result","isAsync","res","reject","Error","dispatch","setTimeout","indexOf","push","j","dispatchPossiblyUnhandledError","asyncReject","chain","firstPromise","secondPromise","onSuccess","onError","catch","undefined","finally","onFinally","try","timeout","time","clearTimeout","toPromise","TypeError","all","promises","count","results","prom","hash","awaitPromises","map","items","method","onPossiblyUnhandledException","cancel","splice","context","args","delay","flush","IE_WIN_ACCESS_ERROR","isAboutProtocol","win","location","protocol","canReadFromWindow","getActualDomain","PROTOCOL","parent","getParent","host","getDomain","domain","mockDomain","iframeWindows","iframeFrames","isWindowClosed","allowMock","closed","message","desc","getOwnPropertyDescriptor","isActuallySameDomain","isSameDomain","mockclosed","top","iframeIndex","collection","safeIndexOf","frame","contentWindow","parentNode","doc","ownerDocument","documentElement","contains","isFrameWindowClosed","isWindow","obj","__cross_domain_utils_window_check__","objectIDs","CrossDomainSafeWeakMap","weakmap","keys","values","Math","random","WeakMap","freeze","testWeakMap","testKey","set","hasNativeWeakMap","_cleanupClosedWindows","delete","isSafeToReadWrite","entry","writable","index","has","getOrSet","getFunctionName","fn","__name__","displayName","setFunctionName","uniqueID","chars","replace","charAt","floor","str","btoa","encodeURIComponent","p1","String","fromCharCode","parseInt","Buffer","from","base64encode","Date","toISOString","slice","toLowerCase","serializeArgs","JSON","stringify","Array","subkey","val","uid","getObjectID","memoizedFunctions","memoize","options","cacheMap","memoizedFunction","cache","thisNamespace","cacheTime","now","reset","noop","objFilter","filter","Boolean","isDocumentReady","document","body","readyState","isDocumentInteractive","isBrowser","clear","interval","setInterval","clearInterval","currentScript","getCurrentScript","getStackTrace","stackDetails","exec","scriptLocation","getElementsByTagName","reverse","script","src","inferCurrentScript","currentUID","getAttribute","setAttribute","headerBuilders","LOG_LEVEL","DEBUG","INFO","WARN","ERROR","FILE","AUTO_FLUSH_LEVEL","LOG_LEVEL_PRIORITY","DEFAULT_LOG_LEVEL","httpTransport","url","headers","json","enableSendBeacon","hasHeaders","navigator","sendBeacon","Blob","blob","type","data","normalizedHeaders","builtHeaders","headerBuilder","xhr","XMLHttpRequest","addEventListener","responseHeaders","rawHeaders","trim","split","join","parseHeaders","getAllResponseHeaders","status","contentType","isJSON","responseBody","responseText","parse","evt","open","setRequestHeader","ontimeout","send","request","extendIfDefined","Logger","prefix","logLevel","transport","flushInterval","events","tracking","payloadBuilders","metaBuilders","trackingBuilders","print","level","event","payload","console","log","warning","immediateFlush","meta","builder","localPromise","logger","logPayload","timestamp","enqueue","addBuilder","builders","loop","safeInterval","debug","info","warn","track","trackingPayload","addPayloadBuilder","addMetaBuilder","addTrackingBuilder","addHeaderBuilder","setTransport","newTransport"],"mappings":"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","file":"beaver-logger.min.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"beaver\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"beaver\"] = factory();\n\telse\n\t\troot[\"beaver\"] = factory();\n})((typeof self !== 'undefined' ? self : this), function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n","export default function _extends() {\n _extends = Object.assign || function (target) {\n for (var i = 1; i < arguments.length; i++) {\n var source = arguments[i];\n\n for (var key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n target[key] = source[key];\n }\n }\n }\n\n return target;\n };\n\n return _extends.apply(this, arguments);\n}","/* @flow */\n\nexport function isPromise(item : mixed) : boolean {\n try {\n if (!item) {\n return false;\n }\n\n if (typeof Promise !== 'undefined' && item instanceof Promise) {\n return true;\n }\n\n if (typeof window !== 'undefined' && typeof window.Window === 'function' && item instanceof window.Window) {\n return false;\n }\n\n if (typeof window !== 'undefined' && typeof window.constructor === 'function' && item instanceof window.constructor) {\n return false;\n }\n\n const toString = ({}).toString;\n\n if (toString) {\n const name = toString.call(item);\n\n if (name === '[object Window]' || name === '[object global]' || name === '[object DOMWindow]') {\n return false;\n }\n }\n\n if (typeof item.then === 'function') {\n return true;\n }\n } catch (err) {\n return false;\n }\n\n return false;\n}\n","/* @flow */\n\nimport type { ZalgoPromise } from './promise';\n\nconst dispatchedErrors = [];\nconst possiblyUnhandledPromiseHandlers : Array<(mixed, promise? : ZalgoPromise) => void> = [];\n\nexport function dispatchPossiblyUnhandledError(err : mixed, promise : ZalgoPromise) {\n\n if (dispatchedErrors.indexOf(err) !== -1) {\n return;\n }\n\n dispatchedErrors.push(err);\n\n setTimeout(() => {\n if (__DEBUG__) {\n // $FlowFixMe\n throw new Error(`${ err.stack || err.toString() }\\n\\nFrom promise:\\n\\n${ promise.stack }`);\n }\n\n throw err;\n }, 1);\n\n for (let j = 0; j < possiblyUnhandledPromiseHandlers.length; j++) {\n // $FlowFixMe\n possiblyUnhandledPromiseHandlers[j](err, promise);\n }\n}\n\nexport function onPossiblyUnhandledException(handler : (mixed, promise? : ZalgoPromise) => void) : {| cancel : () => void |} {\n possiblyUnhandledPromiseHandlers.push(handler);\n\n return {\n cancel() {\n possiblyUnhandledPromiseHandlers.splice(possiblyUnhandledPromiseHandlers.indexOf(handler), 1);\n }\n };\n}\n","/* @flow */\n\nimport type { ZalgoPromise } from './promise';\n\nlet activeCount = 0;\nlet flushPromise;\n\nfunction flushActive() {\n if (!activeCount && flushPromise) {\n const promise = flushPromise;\n flushPromise = null;\n promise.resolve();\n }\n}\n\nexport function startActive() {\n activeCount += 1;\n}\n\nexport function endActive() {\n activeCount -= 1;\n flushActive();\n}\n\nexport function awaitActive(Zalgo : Class>) : ZalgoPromise { // eslint-disable-line no-undef\n const promise = flushPromise = flushPromise || new Zalgo();\n flushActive();\n return promise;\n}\n","/* @flow */\n\nimport { isPromise } from './utils';\nimport { onPossiblyUnhandledException, dispatchPossiblyUnhandledError } from './exceptions';\nimport { startActive, endActive, awaitActive } from './flush';\n\nexport class ZalgoPromise {\n\n resolved : boolean\n rejected : boolean\n errorHandled : boolean\n value : R\n error : mixed\n // eslint-disable-next-line flowtype/no-mutable-array\n handlers : Array<{|\n promise : ZalgoPromise<*>,\n onSuccess : void | (result : R) => mixed,\n onError : void | (error : mixed) => mixed\n |}>\n dispatching : boolean\n stack : string\n\n constructor(handler : ?(resolve : (result : R) => void, reject : (error : mixed) => void) => void) {\n\n this.resolved = false;\n this.rejected = false;\n this.errorHandled = false;\n\n this.handlers = [];\n\n if (handler) {\n\n let result;\n let error;\n let resolved = false;\n let rejected = false;\n let isAsync = false;\n\n startActive();\n\n try {\n handler(res => {\n if (isAsync) {\n this.resolve(res);\n } else {\n resolved = true;\n result = res;\n }\n\n }, err => {\n if (isAsync) {\n this.reject(err);\n } else {\n rejected = true;\n error = err;\n }\n });\n\n } catch (err) {\n endActive();\n this.reject(err);\n return;\n }\n\n endActive();\n\n isAsync = true;\n\n if (resolved) {\n // $FlowFixMe\n this.resolve(result);\n } else if (rejected) {\n this.reject(error);\n }\n }\n\n if (__DEBUG__) {\n try {\n throw new Error(`ZalgoPromise`);\n } catch (err) {\n this.stack = err.stack;\n }\n }\n }\n\n resolve(result : R) : ZalgoPromise {\n if (this.resolved || this.rejected) {\n return this;\n }\n\n if (isPromise(result)) {\n throw new Error('Can not resolve promise with another promise');\n }\n\n this.resolved = true;\n this.value = result;\n this.dispatch();\n\n return this;\n }\n\n reject(error : mixed) : ZalgoPromise {\n if (this.resolved || this.rejected) {\n return this;\n }\n\n if (isPromise(error)) {\n throw new Error('Can not reject promise with another promise');\n }\n\n if (!error) {\n // $FlowFixMe\n const err = (error && typeof error.toString === 'function' ? error.toString() : Object.prototype.toString.call(error));\n error = new Error(`Expected reject to be called with Error, got ${ err }`);\n }\n\n this.rejected = true;\n this.error = error;\n\n if (!this.errorHandled) {\n setTimeout(() => {\n if (!this.errorHandled) {\n dispatchPossiblyUnhandledError(error, this);\n }\n }, 1);\n }\n\n this.dispatch();\n\n return this;\n }\n\n asyncReject(error : mixed) : ZalgoPromise {\n this.errorHandled = true;\n this.reject(error);\n return this;\n }\n \n dispatch() {\n\n const { dispatching, resolved, rejected, handlers } = this;\n\n if (dispatching) {\n return;\n }\n\n if (!resolved && !rejected) {\n return;\n }\n\n this.dispatching = true;\n startActive();\n\n const chain = (firstPromise : ZalgoPromise, secondPromise : ZalgoPromise) => {\n return firstPromise.then(res => {\n secondPromise.resolve(res);\n }, err => {\n secondPromise.reject(err);\n });\n };\n\n for (let i = 0; i < handlers.length; i++) {\n\n const { onSuccess, onError, promise } = handlers[i];\n\n let result;\n\n if (resolved) {\n\n try {\n result = onSuccess ? onSuccess(this.value) : this.value;\n } catch (err) {\n promise.reject(err);\n continue;\n }\n\n } else if (rejected) {\n\n if (!onError) {\n promise.reject(this.error);\n continue;\n }\n\n try {\n result = onError(this.error);\n } catch (err) {\n promise.reject(err);\n continue;\n }\n }\n\n if (result instanceof ZalgoPromise && (result.resolved || result.rejected)) {\n\n if (result.resolved) {\n promise.resolve(result.value);\n } else {\n promise.reject(result.error);\n }\n\n result.errorHandled = true;\n\n } else if (isPromise(result)) {\n\n if (result instanceof ZalgoPromise && (result.resolved || result.rejected)) {\n if (result.resolved) {\n promise.resolve(result.value);\n } else {\n promise.reject(result.error);\n }\n\n } else {\n // $FlowFixMe\n chain(result, promise);\n }\n\n } else {\n\n promise.resolve(result);\n }\n }\n\n handlers.length = 0;\n this.dispatching = false;\n endActive();\n }\n\n then(onSuccess : void | (result : R) => (ZalgoPromise | Y), onError : void | (error : mixed) => (ZalgoPromise | Y)) : ZalgoPromise {\n\n if (onSuccess && typeof onSuccess !== 'function' && !onSuccess.call) {\n throw new Error('Promise.then expected a function for success handler');\n }\n\n if (onError && typeof onError !== 'function' && !onError.call) {\n throw new Error('Promise.then expected a function for error handler');\n }\n\n const promise : ZalgoPromise = new ZalgoPromise();\n\n this.handlers.push({\n promise,\n onSuccess,\n onError\n });\n\n this.errorHandled = true;\n\n this.dispatch();\n\n return promise;\n }\n\n catch(onError : (error : mixed) => ZalgoPromise | Y) : ZalgoPromise {\n return this.then(undefined, onError);\n }\n\n finally(onFinally : () => mixed) : ZalgoPromise {\n\n if (onFinally && typeof onFinally !== 'function' && !onFinally.call) {\n throw new Error('Promise.finally expected a function');\n }\n\n return this.then((result) => {\n return ZalgoPromise.try(onFinally)\n .then(() => {\n return result;\n });\n }, (err) => {\n return ZalgoPromise.try(onFinally)\n .then(() => {\n throw err;\n });\n });\n }\n\n timeout(time : number, err : ?Error) : ZalgoPromise {\n\n if (this.resolved || this.rejected) {\n return this;\n }\n\n const timeout = setTimeout(() => {\n\n if (this.resolved || this.rejected) {\n return;\n }\n\n this.reject(err || new Error(`Promise timed out after ${ time }ms`));\n\n }, time);\n\n return this.then(result => {\n clearTimeout(timeout);\n return result;\n });\n }\n\n // $FlowFixMe\n toPromise() : Promise {\n // $FlowFixMe\n if (typeof Promise === 'undefined') {\n throw new TypeError(`Could not find Promise`);\n }\n // $FlowFixMe\n return Promise.resolve(this); // eslint-disable-line compat/compat\n }\n\n static resolve(value : X | ZalgoPromise) : ZalgoPromise {\n\n if (value instanceof ZalgoPromise) {\n return value;\n }\n\n if (isPromise(value)) {\n // $FlowFixMe\n return new ZalgoPromise((resolve, reject) => value.then(resolve, reject));\n }\n\n return new ZalgoPromise().resolve(value);\n }\n\n static reject(error : mixed) : ZalgoPromise {\n return new ZalgoPromise().reject(error);\n }\n\n static asyncReject(error : mixed) : ZalgoPromise {\n return new ZalgoPromise().asyncReject(error);\n }\n\n static all>(promises : X) : ZalgoPromise<$TupleMap(ZalgoPromise | Y) => Y>> { // eslint-disable-line no-undef\n\n const promise = new ZalgoPromise();\n let count = promises.length;\n const results = [];\n\n if (!count) {\n promise.resolve(results);\n return promise;\n }\n\n const chain = (i : number, firstPromise : ZalgoPromise, secondPromise : ZalgoPromise) => {\n return firstPromise.then(res => {\n results[i] = res;\n count -= 1;\n if (count === 0) {\n promise.resolve(results);\n }\n }, err => {\n secondPromise.reject(err);\n });\n };\n\n for (let i = 0; i < promises.length; i++) {\n const prom = promises[i];\n\n if (prom instanceof ZalgoPromise) {\n if (prom.resolved) {\n results[i] = prom.value;\n count -= 1;\n continue;\n }\n } else if (!isPromise(prom)) {\n results[i] = prom;\n count -= 1;\n continue;\n }\n\n chain(i, ZalgoPromise.resolve(prom), promise);\n }\n\n if (count === 0) {\n promise.resolve(results);\n }\n\n return promise;\n }\n\n static hash(promises : O) : ZalgoPromise<$ObjMap(ZalgoPromise | Y) => Y>> { // eslint-disable-line no-undef\n const result = {};\n const awaitPromises = [];\n\n for (const key in promises) {\n if (promises.hasOwnProperty(key)) {\n const value = promises[key];\n\n if (isPromise(value)) {\n awaitPromises.push(value.then(res => {\n result[key] = res;\n }));\n } else {\n result[key] = value;\n }\n }\n }\n \n return ZalgoPromise.all(awaitPromises).then(() => result);\n }\n\n static map(items : $ReadOnlyArray, method : (T) => (ZalgoPromise | X)) : ZalgoPromise<$ReadOnlyArray> {\n // $FlowFixMe\n return ZalgoPromise.all(items.map(method));\n }\n\n static onPossiblyUnhandledException(handler : (err : mixed) => void) : {| cancel : () => void |} {\n return onPossiblyUnhandledException(handler);\n }\n\n static try>(method : (...args : A) => (ZalgoPromise | Y), context : ?C, args : ?A) : ZalgoPromise {\n\n if (method && typeof method !== 'function' && !method.call) {\n throw new Error('Promise.try expected a function');\n }\n\n let result;\n\n startActive();\n \n try {\n // $FlowFixMe\n result = method.apply(context, args || []);\n } catch (err) {\n endActive();\n return ZalgoPromise.reject(err);\n }\n\n endActive();\n\n return ZalgoPromise.resolve(result);\n }\n\n static delay(delay : number) : ZalgoPromise {\n return new ZalgoPromise(resolve => {\n setTimeout(resolve, delay);\n });\n }\n\n static isPromise(value : mixed) : boolean {\n\n if (value && value instanceof ZalgoPromise) {\n return true;\n }\n\n return isPromise(value);\n }\n\n static flush() : ZalgoPromise {\n return awaitActive(ZalgoPromise);\n }\n}\n","/* @flow */\n/* eslint max-lines: 0 */\n\nimport { isRegex, noop } from './util';\nimport type { CrossDomainWindowType, SameDomainWindowType, DomainMatcher } from './types';\nimport { PROTOCOL, WILDCARD } from './constants';\n\nconst IE_WIN_ACCESS_ERROR = 'Call was rejected by callee.\\r\\n';\n\nexport function isFileProtocol(win : SameDomainWindowType = window) : boolean {\n return win.location.protocol === PROTOCOL.FILE;\n}\n\nexport function isAboutProtocol(win : SameDomainWindowType = window) : boolean {\n return win.location.protocol === PROTOCOL.ABOUT;\n}\n\nexport function getParent(win? : CrossDomainWindowType = window) : ?CrossDomainWindowType {\n\n if (!win) {\n return;\n }\n\n try {\n if (win.parent && win.parent !== win) {\n return win.parent;\n }\n } catch (err) {\n // pass\n }\n}\n\nexport function getOpener(win? : CrossDomainWindowType = window) : ?CrossDomainWindowType {\n\n if (!win) {\n return;\n }\n\n // Make sure we're not actually an iframe which has had window.open() called on us\n if (getParent(win)) {\n return;\n }\n\n try {\n return win.opener;\n } catch (err) {\n // pass\n }\n}\n\nexport function canReadFromWindow(win : CrossDomainWindowType | SameDomainWindowType) : boolean {\n try {\n // $FlowFixMe\n noop(win && win.location && win.location.href);\n return true;\n } catch (err) {\n // pass\n }\n\n return false;\n}\n\nexport function getActualDomain(win? : SameDomainWindowType = window) : string {\n\n const location = win.location;\n\n if (!location) {\n throw new Error(`Can not read window location`);\n }\n\n const protocol = location.protocol;\n\n if (!protocol) {\n throw new Error(`Can not read window protocol`);\n }\n\n if (protocol === PROTOCOL.FILE) {\n return `${ PROTOCOL.FILE }//`;\n }\n\n if (protocol === PROTOCOL.ABOUT) {\n\n const parent = getParent(win);\n if (parent && canReadFromWindow(parent)) {\n // $FlowFixMe\n return getActualDomain(parent);\n }\n\n return `${ PROTOCOL.ABOUT }//`;\n }\n\n const host = location.host;\n\n if (!host) {\n throw new Error(`Can not read window host`);\n }\n\n return `${ protocol }//${ host }`;\n}\n\nexport function getDomain(win? : SameDomainWindowType = window) : string {\n\n const domain = getActualDomain(win);\n\n if (domain && win.mockDomain && win.mockDomain.indexOf(PROTOCOL.MOCK) === 0) {\n return win.mockDomain;\n }\n\n return domain;\n}\n\nexport function isBlankDomain(win : CrossDomainWindowType) : boolean {\n try {\n // $FlowFixMe\n if (!win.location.href) {\n return true;\n }\n\n if (win.location.href === 'about:blank') {\n return true;\n }\n } catch (err) {\n // pass\n }\n\n return false;\n}\n\nexport function isActuallySameDomain(win : CrossDomainWindowType) : boolean {\n\n try {\n if (win === window) {\n return true;\n }\n\n } catch (err) {\n // pass\n }\n\n try {\n const desc = Object.getOwnPropertyDescriptor(win, 'location');\n\n if (desc && desc.enumerable === false) {\n return false;\n }\n\n } catch (err) {\n // pass\n }\n\n try {\n // $FlowFixMe\n if (isAboutProtocol(win) && canReadFromWindow(win)) {\n return true;\n }\n } catch (err) {\n // pass\n }\n\n try {\n // $FlowFixMe\n if (getActualDomain(win) === getActualDomain(window)) {\n return true;\n }\n\n } catch (err) {\n // pass\n }\n\n return false;\n}\n\nexport function isSameDomain(win : CrossDomainWindowType | SameDomainWindowType) : boolean {\n\n if (!isActuallySameDomain(win)) {\n return false;\n }\n\n try {\n\n if (win === window) {\n return true;\n }\n\n // $FlowFixMe\n if (isAboutProtocol(win) && canReadFromWindow(win)) {\n return true;\n }\n\n // $FlowFixMe\n if (getDomain(window) === getDomain(win)) {\n return true;\n }\n\n } catch (err) {\n // pass\n }\n\n return false;\n}\n\n\nexport function assertSameDomain(win : CrossDomainWindowType | SameDomainWindowType) : SameDomainWindowType {\n if (!isSameDomain(win)) {\n throw new Error(`Expected window to be same domain`);\n }\n\n // $FlowFixMe\n return win;\n}\n\nexport function getParents(win : CrossDomainWindowType) : $ReadOnlyArray {\n\n const result = [];\n\n try {\n\n while (win.parent !== win) {\n result.push(win.parent);\n win = win.parent;\n }\n\n } catch (err) {\n // pass\n }\n\n return result;\n}\n\nexport function isAncestorParent(parent : CrossDomainWindowType, child : CrossDomainWindowType) : boolean {\n\n if (!parent || !child) {\n return false;\n }\n\n const childParent = getParent(child);\n\n if (childParent) {\n return childParent === parent;\n }\n\n if (getParents(child).indexOf(parent) !== -1) {\n return true;\n }\n\n return false;\n}\n\nexport function getFrames(win : CrossDomainWindowType) : $ReadOnlyArray {\n\n const result = [];\n\n let frames;\n\n try {\n frames = win.frames;\n } catch (err) {\n frames = win;\n }\n\n let len;\n\n try {\n len = frames.length;\n } catch (err) {\n // pass\n }\n\n if (len === 0) {\n return result;\n }\n\n if (len) {\n for (let i = 0; i < len; i++) {\n\n let frame;\n\n try {\n frame = frames[i];\n } catch (err) {\n continue;\n }\n\n result.push(frame);\n }\n\n return result;\n }\n\n for (let i = 0; i < 100; i++) {\n let frame;\n\n try {\n frame = frames[i];\n } catch (err) {\n return result;\n }\n\n if (!frame) {\n return result;\n }\n\n result.push(frame);\n }\n\n return result;\n}\n\n\nexport function getAllChildFrames(win : CrossDomainWindowType) : $ReadOnlyArray {\n\n const result = [];\n\n for (const frame of getFrames(win)) {\n result.push(frame);\n\n for (const childFrame of getAllChildFrames(frame)) {\n result.push(childFrame);\n }\n }\n\n return result;\n}\n\nexport function getTop(win? : CrossDomainWindowType = window) : ?CrossDomainWindowType {\n\n try {\n if (win.top) {\n return win.top;\n }\n } catch (err) {\n // pass\n }\n\n if (getParent(win) === win) {\n return win;\n }\n\n try {\n if (isAncestorParent(window, win) && window.top) {\n return window.top;\n }\n } catch (err) {\n // pass\n }\n\n try {\n if (isAncestorParent(win, window) && window.top) {\n return window.top;\n }\n } catch (err) {\n // pass\n }\n\n for (const frame of getAllChildFrames(win)) {\n try {\n if (frame.top) {\n return frame.top;\n }\n } catch (err) {\n // pass\n }\n\n if (getParent(frame) === frame) {\n return frame;\n }\n }\n}\n\nexport function getNextOpener(win? : CrossDomainWindowType = window) : ?CrossDomainWindowType {\n return getOpener(getTop(win) || win);\n}\n\nexport function getUltimateTop(win? : CrossDomainWindowType = window) : CrossDomainWindowType {\n const opener = getNextOpener(win);\n\n if (opener) {\n return getUltimateTop(opener);\n }\n\n return top;\n}\n\nexport function getAllFramesInWindow(win : CrossDomainWindowType) : $ReadOnlyArray {\n const top = getTop(win);\n\n if (!top) {\n throw new Error(`Can not determine top window`);\n }\n\n let result = [ ...getAllChildFrames(top), top ];\n\n // Win may be in shadow dom\n if (result.indexOf(win) === -1) {\n result = [ ...result, win, ...getAllChildFrames(win) ];\n }\n\n return result;\n}\n\nexport function getAllWindows(win? : CrossDomainWindowType = window) : $ReadOnlyArray {\n const frames = getAllFramesInWindow(win);\n const opener = getNextOpener(win);\n\n if (opener) {\n return [ ...getAllWindows(opener), ...frames ];\n } else {\n return frames;\n }\n}\n\nexport function isTop(win : CrossDomainWindowType) : boolean {\n return win === getTop(win);\n}\n\nexport function isFrameWindowClosed(frame : HTMLIFrameElement) : boolean {\n\n if (!frame.contentWindow) {\n return true;\n }\n\n if (!frame.parentNode) {\n return true;\n }\n\n const doc = frame.ownerDocument;\n\n if (doc && doc.documentElement && !doc.documentElement.contains(frame)) {\n let parent = frame;\n\n while (parent.parentNode && parent.parentNode !== parent) {\n parent = parent.parentNode;\n }\n\n // $FlowFixMe\n if (!parent.host || !doc.documentElement.contains(parent.host)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction safeIndexOf(collection : $ReadOnlyArray, item : T) : number {\n for (let i = 0; i < collection.length; i++) {\n\n try {\n if (collection[i] === item) {\n return i;\n }\n } catch (err) {\n // pass\n }\n }\n\n return -1;\n}\n\nconst iframeWindows = [];\nconst iframeFrames = [];\n\nexport function isWindowClosed(win : CrossDomainWindowType, allowMock : boolean = true) : boolean {\n\n try {\n if (win === window) {\n return false;\n }\n } catch (err) {\n return true;\n }\n\n try {\n if (!win) {\n return true;\n }\n\n } catch (err) {\n return true;\n }\n\n try {\n if (win.closed) {\n return true;\n }\n\n } catch (err) {\n\n // I love you so much IE\n\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return false;\n }\n\n return true;\n }\n\n\n if (allowMock && isSameDomain(win)) {\n try {\n // $FlowFixMe\n if (win.mockclosed) {\n return true;\n }\n } catch (err) {\n // pass\n }\n }\n\n // Mobile safari\n\n try {\n if (!win.parent || !win.top) {\n return true;\n }\n } catch (err) {\n // pass\n }\n\n // Yes, this actually happens in IE. win === win errors out when the window\n // is from an iframe, and the iframe was removed from the page.\n\n try {\n noop(win === win); // eslint-disable-line no-self-compare\n } catch (err) {\n return true;\n }\n\n // IE orphaned frame\n\n const iframeIndex = safeIndexOf(iframeWindows, win);\n\n if (iframeIndex !== -1) {\n const frame = iframeFrames[iframeIndex];\n\n if (frame && isFrameWindowClosed(frame)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction cleanIframes() {\n for (let i = 0; i < iframeWindows.length; i++) {\n let closed = false;\n\n try {\n closed = iframeWindows[i].closed;\n } catch (err) {\n // pass\n }\n\n if (closed) {\n iframeFrames.splice(i, 1);\n iframeWindows.splice(i, 1);\n }\n }\n}\n\nexport function linkFrameWindow(frame : HTMLIFrameElement) {\n\n cleanIframes();\n\n if (frame && frame.contentWindow) {\n try {\n iframeWindows.push(frame.contentWindow);\n iframeFrames.push(frame);\n } catch (err) {\n // pass\n }\n }\n}\n\nexport function getUserAgent(win : ?SameDomainWindowType) : string {\n win = win || window;\n return win.navigator.mockUserAgent || win.navigator.userAgent;\n}\n\n\nexport function getFrameByName(win : CrossDomainWindowType, name : string) : ?CrossDomainWindowType {\n\n const winFrames = getFrames(win);\n\n for (const childFrame of winFrames) {\n try {\n // $FlowFixMe\n if (isSameDomain(childFrame) && childFrame.name === name && winFrames.indexOf(childFrame) !== -1) {\n return childFrame;\n }\n } catch (err) {\n // pass\n }\n }\n\n try {\n // $FlowFixMe\n if (winFrames.indexOf(win.frames[name]) !== -1) {\n // $FlowFixMe\n return win.frames[name];\n }\n } catch (err) {\n // pass\n }\n\n try {\n if (winFrames.indexOf(win[name]) !== -1) {\n return win[name];\n }\n } catch (err) {\n // pass\n }\n}\n\nexport function findChildFrameByName(win : CrossDomainWindowType, name : string) : ?CrossDomainWindowType {\n\n const frame = getFrameByName(win, name);\n\n if (frame) {\n return frame;\n }\n\n for (const childFrame of getFrames(win)) {\n const namedFrame = findChildFrameByName(childFrame, name);\n\n if (namedFrame) {\n return namedFrame;\n }\n }\n}\n\nexport function findFrameByName(win : CrossDomainWindowType, name : string) : ?CrossDomainWindowType {\n const frame = getFrameByName(win, name);\n\n if (frame) {\n return frame;\n }\n\n const top = getTop(win) || win;\n\n return findChildFrameByName(top, name);\n}\n\nexport function isParent(win : CrossDomainWindowType, frame : CrossDomainWindowType) : boolean {\n\n const frameParent = getParent(frame);\n\n if (frameParent) {\n return frameParent === win;\n }\n\n for (const childFrame of getFrames(win)) {\n if (childFrame === frame) {\n return true;\n }\n }\n\n return false;\n}\n\nexport function isOpener(parent : CrossDomainWindowType, child : CrossDomainWindowType) : boolean {\n\n return parent === getOpener(child);\n}\n\nexport function getAncestor(win? : CrossDomainWindowType = window) : ?CrossDomainWindowType {\n win = win || window;\n\n const opener = getOpener(win);\n\n if (opener) {\n return opener;\n }\n\n const parent = getParent(win);\n\n if (parent) {\n return parent;\n }\n}\n\nexport function getAncestors(win : CrossDomainWindowType) : $ReadOnlyArray {\n\n const results = [];\n\n let ancestor = win;\n\n while (ancestor) {\n ancestor = getAncestor(ancestor);\n if (ancestor) {\n results.push(ancestor);\n }\n }\n\n return results;\n}\n\n\nexport function isAncestor(parent : CrossDomainWindowType, child : CrossDomainWindowType) : boolean {\n\n const actualParent = getAncestor(child);\n\n if (actualParent) {\n if (actualParent === parent) {\n return true;\n }\n\n return false;\n }\n\n if (child === parent) {\n return false;\n }\n\n if (getTop(child) === child) {\n return false;\n }\n\n for (const frame of getFrames(parent)) {\n if (frame === child) {\n return true;\n }\n }\n\n return false;\n}\n\nexport function isPopup(win? : CrossDomainWindowType = window) : boolean {\n return Boolean(getOpener(win));\n}\n\nexport function isIframe(win? : CrossDomainWindowType = window) : boolean {\n return Boolean(getParent(win));\n}\n\nexport function isFullpage(win? : CrossDomainWindowType = window) : boolean {\n return Boolean(!isIframe(win) && !isPopup(win));\n}\n\nfunction anyMatch(collection1, collection2) : boolean {\n\n for (const item1 of collection1) {\n for (const item2 of collection2) {\n if (item1 === item2) {\n return true;\n }\n }\n }\n\n return false;\n}\n\nexport function getDistanceFromTop(win : CrossDomainWindowType = window) : number {\n let distance = 0;\n let parent = win;\n\n while (parent) {\n parent = getParent(parent);\n if (parent) {\n distance += 1;\n }\n }\n\n return distance;\n}\n\nexport function getNthParent(win : CrossDomainWindowType, n : number = 1) : ?CrossDomainWindowType {\n let parent = win;\n\n for (let i = 0; i < n; i++) {\n if (!parent) {\n return;\n }\n\n parent = getParent(parent);\n }\n\n return parent;\n}\n\nexport function getNthParentFromTop(win : CrossDomainWindowType, n : number = 1) : ?CrossDomainWindowType {\n return getNthParent(win, getDistanceFromTop(win) - n);\n}\n\nexport function isSameTopWindow(win1 : CrossDomainWindowType, win2 : CrossDomainWindowType) : boolean {\n\n const top1 = getTop(win1) || win1;\n const top2 = getTop(win2) || win2;\n\n try {\n if (top1 && top2) {\n if (top1 === top2) {\n return true;\n }\n\n return false;\n }\n } catch (err) {\n // pass\n }\n\n const allFrames1 = getAllFramesInWindow(win1);\n const allFrames2 = getAllFramesInWindow(win2);\n\n if (anyMatch(allFrames1, allFrames2)) {\n return true;\n }\n\n const opener1 = getOpener(top1);\n const opener2 = getOpener(top2);\n\n if (opener1 && anyMatch(getAllFramesInWindow(opener1), allFrames2)) {\n return false;\n }\n\n if (opener2 && anyMatch(getAllFramesInWindow(opener2), allFrames1)) {\n return false;\n }\n\n return false;\n}\n\nexport function matchDomain(pattern : DomainMatcher, origin : DomainMatcher) : boolean {\n\n if (typeof pattern === 'string') {\n\n if (typeof origin === 'string') {\n return pattern === WILDCARD || origin === pattern;\n }\n\n if (isRegex(origin)) {\n return false;\n }\n\n if (Array.isArray(origin)) {\n return false;\n }\n }\n\n if (isRegex(pattern)) {\n\n if (isRegex(origin)) {\n return pattern.toString() === origin.toString();\n }\n\n if (Array.isArray(origin)) {\n return false;\n }\n\n // $FlowFixMe\n return Boolean(origin.match(pattern));\n }\n\n if (Array.isArray(pattern)) {\n\n if (Array.isArray(origin)) {\n return JSON.stringify(pattern) === JSON.stringify(origin);\n }\n\n if (isRegex(origin)) {\n return false;\n }\n\n return pattern.some(subpattern => matchDomain(subpattern, origin));\n }\n\n return false;\n}\n\nexport function stringifyDomainPattern(pattern : DomainMatcher) : string {\n if (Array.isArray(pattern)) {\n return `(${ pattern.join(' | ') })`;\n } else if (isRegex(pattern)) {\n return `RegExp(${ pattern.toString() }`;\n } else {\n return pattern.toString();\n }\n}\n\nexport function getDomainFromUrl(url : string) : string {\n\n let domain;\n\n if (url.match(/^(https?|mock|file):\\/\\//)) {\n domain = url;\n } else {\n return getDomain();\n }\n\n domain = domain.split('/').slice(0, 3).join('/');\n\n return domain;\n}\n\nexport function onCloseWindow(win : CrossDomainWindowType, callback : Function, delay : number = 1000, maxtime : number = Infinity) : {| cancel : () => void |} {\n\n let timeout;\n\n const check = () => {\n\n if (isWindowClosed(win)) {\n\n if (timeout) {\n clearTimeout(timeout);\n }\n\n return callback();\n }\n\n if (maxtime <= 0) {\n clearTimeout(timeout);\n } else {\n maxtime -= delay;\n timeout = setTimeout(check, delay);\n }\n };\n\n check();\n\n return {\n cancel() {\n if (timeout) {\n clearTimeout(timeout);\n }\n }\n };\n}\n\n// eslint-disable-next-line complexity\nexport function isWindow(obj : Object) : boolean {\n\n try {\n if (obj === window) {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (Object.prototype.toString.call(obj) === '[object Window]') {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (window.Window && obj instanceof window.Window) {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (obj && obj.self === obj) {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (obj && obj.parent === obj) {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (obj && obj.top === obj) {\n return true;\n }\n } catch (err) {\n if (err && err.message === IE_WIN_ACCESS_ERROR) {\n return true;\n }\n }\n\n try {\n if (noop(obj === obj) === '__unlikely_value__') { // eslint-disable-line no-self-compare\n return false;\n }\n\n } catch (err) {\n return true;\n }\n\n try {\n if (obj && obj.__cross_domain_utils_window_check__ === '__unlikely_value__') {\n return false;\n }\n\n } catch (err) {\n return true;\n }\n\n try {\n if ('postMessage' in obj && 'self' in obj && 'location' in obj) {\n return true;\n }\n } catch (err) {\n // pass\n }\n\n return false;\n}\n\nexport function isBrowser() : boolean {\n return (typeof window !== 'undefined' && typeof window.location !== 'undefined');\n}\n\nexport function isCurrentDomain(domain : string) : boolean {\n if (!isBrowser()) {\n return false;\n }\n\n return (getDomain() === domain);\n}\n\nexport function isMockDomain(domain : string) : boolean {\n return domain.indexOf(PROTOCOL.MOCK) === 0;\n}\n\nexport function normalizeMockUrl(url : string) : string {\n if (!isMockDomain(getDomainFromUrl(url))) {\n return url;\n }\n\n if (!__TEST__) {\n throw new Error(`Mock urls not supported out of test mode`);\n }\n\n return url.replace(/^mock:\\/\\/[^/]+/, getActualDomain(window));\n}\n\nexport function closeWindow(win : CrossDomainWindowType) {\n try {\n win.close();\n } catch (err) {\n // pass\n }\n}\n\nexport function getFrameForWindow(win : CrossDomainWindowType) : ?HTMLElement {\n if (isSameDomain(win)) {\n return assertSameDomain(win).frameElement;\n }\n\n for (const frame of document.querySelectorAll('iframe')) {\n if (frame && frame.contentWindow && frame.contentWindow === win) {\n return frame;\n }\n }\n}\n","/* @flow */\n\nexport const PROTOCOL = {\n MOCK: ('mock:' : 'mock:'),\n FILE: ('file:' : 'file:'),\n ABOUT: ('about:' : 'about:')\n};\n\nexport const WILDCARD = '*';\n\nexport const WINDOW_TYPE = {\n IFRAME: ('iframe' : 'iframe'),\n POPUP: ('popup' : 'popup')\n};\n","/* @flow */\n\nexport function safeIndexOf(collection : Array, item : T) : number {\n for (let i = 0; i < collection.length; i++) {\n\n try {\n if (collection[i] === item) {\n return i;\n }\n } catch (err) {\n // pass\n }\n }\n\n return -1;\n}\n\n// eslint-disable-next-line no-unused-vars\nexport function noop(...args : Array) {\n // pass\n}\n","/* @flow */\n\nimport { isWindow, isWindowClosed } from 'cross-domain-utils/src';\n\nimport { hasNativeWeakMap } from './native';\nimport { noop, safeIndexOf } from './util';\n\nexport class CrossDomainSafeWeakMap {\n\n name : string\n weakmap : ?WeakMap\n keys : Array\n values : Array\n\n constructor() {\n // eslint-disable-next-line no-bitwise\n this.name = `__weakmap_${ Math.random() * 1e9 >>> 0 }__`;\n\n if (hasNativeWeakMap()) {\n try {\n this.weakmap = new WeakMap();\n } catch (err) {\n // pass\n }\n }\n\n this.keys = [];\n this.values = [];\n }\n\n _cleanupClosedWindows() {\n\n let weakmap = this.weakmap;\n let keys = this.keys;\n\n for (let i = 0; i < keys.length; i++) {\n let value = keys[i];\n\n if (isWindow(value) && isWindowClosed(value)) {\n\n if (weakmap) {\n try {\n weakmap.delete(value);\n } catch (err) {\n // pass\n }\n }\n\n keys.splice(i, 1);\n this.values.splice(i, 1);\n\n i -= 1;\n }\n }\n }\n\n isSafeToReadWrite(key : K) : boolean {\n\n if (isWindow(key)) {\n return false;\n }\n\n try {\n noop(key && key.self);\n noop(key && key[this.name]);\n } catch (err) {\n return false;\n }\n\n return true;\n }\n\n set(key : K, value : V) {\n\n if (!key) {\n throw new Error(`WeakMap expected key`);\n }\n\n let weakmap = this.weakmap;\n\n if (weakmap) {\n try {\n weakmap.set(key, value);\n } catch (err) {\n delete this.weakmap;\n }\n }\n\n if (this.isSafeToReadWrite(key)) {\n try {\n let name = this.name;\n let entry = key[name];\n\n if (entry && entry[0] === key) {\n entry[1] = value;\n } else {\n Object.defineProperty(key, name, {\n value: [ key, value ],\n writable: true\n });\n }\n\n return;\n\n } catch (err) {\n // pass\n }\n }\n\n this._cleanupClosedWindows();\n\n let keys = this.keys;\n let values = this.values;\n let index = safeIndexOf(keys, key);\n\n if (index === -1) {\n keys.push(key);\n values.push(value);\n } else {\n values[index] = value;\n }\n }\n\n get(key : K) : V | void {\n\n if (!key) {\n throw new Error(`WeakMap expected key`);\n }\n\n let weakmap = this.weakmap;\n\n if (weakmap) {\n try {\n if (weakmap.has(key)) {\n return weakmap.get(key);\n }\n \n } catch (err) {\n delete this.weakmap;\n }\n }\n\n if (this.isSafeToReadWrite(key)) {\n try {\n let entry = key[this.name];\n\n if (entry && entry[0] === key) {\n return entry[1];\n }\n\n return;\n } catch (err) {\n // pass\n }\n }\n\n this._cleanupClosedWindows();\n\n let keys = this.keys;\n let index = safeIndexOf(keys, key);\n\n if (index === -1) {\n return;\n }\n\n return this.values[index];\n }\n\n delete(key : K) {\n\n if (!key) {\n throw new Error(`WeakMap expected key`);\n }\n\n let weakmap = this.weakmap;\n\n if (weakmap) {\n try {\n weakmap.delete(key);\n } catch (err) {\n delete this.weakmap;\n }\n }\n\n if (this.isSafeToReadWrite(key)) {\n try {\n let entry = key[this.name];\n\n if (entry && entry[0] === key) {\n entry[0] = entry[1] = undefined;\n }\n } catch (err) {\n // pass\n }\n }\n\n this._cleanupClosedWindows();\n\n let keys = this.keys;\n let index = safeIndexOf(keys, key);\n\n if (index !== -1) {\n keys.splice(index, 1);\n this.values.splice(index, 1);\n }\n }\n\n has(key : K) : boolean {\n\n if (!key) {\n throw new Error(`WeakMap expected key`);\n }\n\n let weakmap = this.weakmap;\n\n if (weakmap) {\n try {\n if (weakmap.has(key)) {\n return true;\n }\n } catch (err) {\n delete this.weakmap;\n }\n }\n\n if (this.isSafeToReadWrite(key)) {\n try {\n let entry = key[this.name];\n\n if (entry && entry[0] === key) {\n return true;\n }\n\n return false;\n } catch (err) {\n // pass\n }\n }\n\n this._cleanupClosedWindows();\n\n let index = safeIndexOf(this.keys, key);\n return index !== -1;\n }\n\n getOrSet(key : K, getter : () => V) : V {\n if (this.has(key)) {\n // $FlowFixMe\n return this.get(key);\n }\n\n let value = getter();\n this.set(key, value);\n return value;\n }\n}\n","\n/* @flow */\n/* eslint max-lines: 0 */\n\nimport { ZalgoPromise } from 'zalgo-promise/src';\nimport { WeakMap } from 'cross-domain-safe-weakmap/src';\n\nimport type { CancelableType } from './types';\n\nexport function getFunctionName (fn : T) : string {\n return fn.name || fn.__name__ || fn.displayName || 'anonymous';\n}\n\nexport function setFunctionName (fn : T, name : string) : T {\n try {\n delete fn.name;\n fn.name = name;\n } catch (err) {\n // pass\n }\n\n fn.__name__ = fn.displayName = name;\n return fn;\n}\n\nexport function base64encode(str : string) : string {\n if (typeof btoa === 'function') {\n return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (m, p1) => {\n return String.fromCharCode(parseInt(p1, 16));\n }));\n }\n\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(str, 'utf8').toString('base64');\n }\n\n throw new Error(`Can not find window.btoa or Buffer`);\n}\n\nexport function base64decode(str : string) : string {\n if (typeof atob === 'function') {\n return decodeURIComponent(Array.prototype.map.call(atob(str), c => {\n // eslint-disable-next-line prefer-template\n return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);\n }).join(''));\n }\n\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(str, 'base64').toString('utf8');\n }\n\n throw new Error(`Can not find window.atob or Buffer`);\n}\n\nexport function uniqueID() : string {\n\n const chars = '0123456789abcdef';\n\n const randomID = 'xxxxxxxxxx'.replace(/./g, () => {\n return chars.charAt(Math.floor(Math.random() * chars.length));\n });\n\n const timeID = base64encode(\n new Date().toISOString().slice(11, 19).replace('T', '.')\n ).replace(/[^a-zA-Z0-9]/g, '').toLowerCase();\n\n return `${ randomID }_${ timeID }`;\n}\n\nexport function getGlobal() : Object {\n if (typeof window !== 'undefined') {\n return window;\n }\n if (typeof global !== 'undefined') {\n return global;\n }\n if (typeof __GLOBAL__ !== 'undefined') {\n return __GLOBAL__;\n }\n throw new Error(`No global found`);\n}\n\nlet objectIDs;\n\nexport function getObjectID(obj : Object) : string {\n\n objectIDs = objectIDs || new WeakMap();\n\n if (obj === null || obj === undefined || (typeof obj !== 'object' && typeof obj !== 'function')) {\n throw new Error(`Invalid object`);\n }\n\n let uid = objectIDs.get(obj);\n\n if (!uid) {\n uid = `${ typeof obj }:${ uniqueID() }`;\n objectIDs.set(obj, uid);\n }\n\n return uid;\n}\n\nfunction serializeArgs(args : $ReadOnlyArray) : string {\n try {\n return JSON.stringify(Array.prototype.slice.call(args), (subkey, val) => {\n if (typeof val === 'function') {\n return `memoize[${ getObjectID(val) }]`;\n }\n return val;\n });\n } catch (err) {\n throw new Error(`Arguments not serializable -- can not be used to memoize`);\n }\n}\ntype MemoizeOptions = {|\n name? : string,\n time? : number,\n thisNamespace? : boolean\n|};\n\nconst getDefaultMemoizeOptions = () : MemoizeOptions => {\n // $FlowFixMe\n return {};\n};\n\nconst memoizedFunctions = [];\n\nexport function memoize(method : F, options? : MemoizeOptions = getDefaultMemoizeOptions()) : F & {| reset : () => void |} {\n const cacheMap = new WeakMap();\n\n const memoizedFunction = function memoizedFunction(...args) : mixed {\n const cache = cacheMap.getOrSet(options.thisNamespace ? this : method, () => ({}));\n\n const key : string = serializeArgs(args);\n\n const cacheTime = options.time;\n if (cache[key] && cacheTime && (Date.now() - cache[key].time) < cacheTime) {\n delete cache[key];\n }\n\n if (cache[key]) {\n return cache[key].value;\n }\n\n const time = Date.now();\n const value = method.apply(this, arguments);\n\n cache[key] = { time, value };\n\n return cache[key].value;\n };\n\n memoizedFunction.reset = () => {\n cacheMap.delete(options.thisNamespace ? this : method);\n };\n\n memoizedFunctions.push(memoizedFunction);\n\n // $FlowFixMe\n const result : F = memoizedFunction;\n\n return setFunctionName(result, `${ options.name || getFunctionName(method) }::memoized`);\n}\n\nmemoize.clear = () => {\n for (const memoizedFunction of memoizedFunctions) {\n memoizedFunction.reset();\n }\n};\n\nexport function promiseIdentity(item : ZalgoPromise | T) : ZalgoPromise {\n // $FlowFixMe\n return ZalgoPromise.resolve(item);\n}\n\n// eslint-disable-next-line flowtype/no-weak-types\nexport function memoizePromise(method : (...args : $ReadOnlyArray) => ZalgoPromise) : ((...args : $ReadOnlyArray) => ZalgoPromise) {\n let cache = {};\n\n // eslint-disable-next-line flowtype/no-weak-types\n function memoizedPromiseFunction(...args : $ReadOnlyArray) : ZalgoPromise {\n const key : string = serializeArgs(args);\n\n if (cache.hasOwnProperty(key)) {\n return cache[key];\n }\n\n cache[key] = ZalgoPromise.try(() => method.apply(this, arguments))\n .finally(() => {\n delete cache[key];\n });\n\n return cache[key];\n }\n\n memoizedPromiseFunction.reset = () => {\n cache = {};\n };\n\n return setFunctionName(memoizedPromiseFunction, `${ getFunctionName(method) }::promiseMemoized`);\n}\n\ntype PromisifyOptions = {|\n name ? : string\n|};\n\nconst getDefaultPromisifyOptions = () : PromisifyOptions => {\n // $FlowFixMe\n return {};\n};\n\n// eslint-disable-next-line flowtype/no-weak-types\nexport function promisify(method : (...args : $ReadOnlyArray) => R, options : PromisifyOptions = getDefaultPromisifyOptions()) : ((...args : $ReadOnlyArray) => ZalgoPromise) {\n function promisifiedFunction() : ZalgoPromise {\n return ZalgoPromise.try(method, this, arguments);\n }\n\n if (options.name) {\n promisifiedFunction.displayName = `${ options.name }:promisified`;\n }\n\n return setFunctionName(promisifiedFunction, `${ getFunctionName(method) }::promisified`);\n}\n\n// eslint-disable-next-line flowtype/no-weak-types\nexport function inlineMemoize(method : (...args : $ReadOnlyArray) => R, logic : (...args : $ReadOnlyArray) => R, args : $ReadOnlyArray = []) : R {\n // $FlowFixMe\n const cache : {| [string] : R |} = method.__inline_memoize_cache__ = method.__inline_memoize_cache__ || {};\n const key = serializeArgs(args);\n\n if (cache.hasOwnProperty(key)) {\n return cache[key];\n }\n \n const result = cache[key] = logic(...args);\n\n return result;\n}\n\n// eslint-disable-next-line no-unused-vars\nexport function noop(...args : $ReadOnlyArray) {\n // pass\n}\n\nexport function once(method : Function) : Function {\n let called = false;\n\n const onceFunction = function() : mixed {\n if (!called) {\n called = true;\n return method.apply(this, arguments);\n }\n };\n\n return setFunctionName(onceFunction, `${ getFunctionName(method) }::once`);\n}\n\nexport function hashStr(str : string) : number {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n hash += str[i].charCodeAt(0) * Math.pow((i % 10) + 1, 5);\n }\n return Math.floor(Math.pow(Math.sqrt(hash), 5));\n}\n\nexport function strHashStr(str : string) : string {\n let hash = '';\n\n for (let i = 0; i < str.length; i++) {\n let total = (str[i].charCodeAt(0) * i);\n\n if (str[i + 1]) {\n total += (str[i + 1].charCodeAt(0) * (i - 1));\n }\n\n hash += String.fromCharCode(97 + (Math.abs(total) % 26));\n }\n\n return hash;\n}\n\nexport function match(str : string, pattern : RegExp) : ?string {\n const regmatch = str.match(pattern);\n if (regmatch) {\n return regmatch[1];\n }\n}\n\nexport function awaitKey(obj : Object, key : string) : ZalgoPromise {\n return new ZalgoPromise(resolve => {\n\n let value = obj[key];\n\n if (value) {\n return resolve(value);\n }\n\n delete obj[key];\n\n Object.defineProperty(obj, key, {\n\n configurable: true,\n\n set(item) {\n value = item;\n\n if (value) {\n resolve(value);\n }\n },\n\n get() : T {\n return value;\n }\n });\n });\n}\n\nexport function stringifyError(err : mixed, level : number = 1) : string {\n\n if (level >= 3) {\n return 'stringifyError stack overflow';\n }\n\n try {\n if (!err) {\n return ``;\n }\n\n if (typeof err === 'string') {\n return err;\n }\n\n if (err instanceof Error) {\n const stack = err && err.stack;\n const message = err && err.message;\n\n if (stack && message) {\n if (stack.indexOf(message) !== -1) {\n return stack;\n } else {\n return `${ message }\\n${ stack }`;\n }\n } else if (stack) {\n return stack;\n } else if (message) {\n return message;\n }\n }\n\n if (err && err.toString && typeof err.toString === 'function') {\n // $FlowFixMe\n return err.toString();\n }\n\n return Object.prototype.toString.call(err);\n\n } catch (newErr) {\n return `Error while stringifying error: ${ stringifyError(newErr, level + 1) }`;\n }\n}\n\nexport function stringifyErrorMessage(err : mixed) : string {\n\n const defaultMessage = ``;\n\n if (!err) {\n return defaultMessage;\n }\n\n if (err instanceof Error) {\n return err.message || defaultMessage;\n }\n\n if (typeof err.message === 'string') {\n return err.message || defaultMessage;\n }\n\n return defaultMessage;\n}\n\nexport function stringify(item : mixed) : string {\n if (typeof item === 'string') {\n return item;\n }\n\n if (item && item.toString && typeof item.toString === 'function') {\n // $FlowFixMe\n return item.toString();\n }\n\n return Object.prototype.toString.call(item);\n}\n\nexport function domainMatches(hostname : string, domain : string) : boolean {\n hostname = hostname.split('://')[1];\n const index = hostname.indexOf(domain);\n return (index !== -1 && hostname.slice(index) === domain);\n}\n\nexport function patchMethod(obj : Object, name : string, handler : Function) {\n const original = obj[name];\n\n obj[name] = function patchedMethod() : mixed {\n return handler({\n context: this,\n args: Array.prototype.slice.call(arguments),\n original,\n callOriginal: () => original.apply(this, arguments)\n });\n };\n}\n\nexport function extend(obj : T, source : Object) : T {\n if (!source) {\n return obj;\n }\n\n if (Object.assign) {\n return Object.assign(obj, source);\n }\n\n for (const key in source) {\n if (source.hasOwnProperty(key)) {\n obj[key] = source[key];\n }\n }\n\n return obj;\n}\n\n// eslint-disable-next-line no-undef\ntype Values = ({ [string] : T }) => $ReadOnlyArray;\n\nexport const values : Values = (obj) => {\n if (Object.values) {\n // $FlowFixMe\n return Object.values(obj);\n }\n\n const result = [];\n for (const key in obj) {\n if (obj.hasOwnProperty(key)) {\n result.push(obj[key]);\n }\n }\n\n // $FlowFixMe\n return result;\n};\n\nexport const memoizedValues : Values = memoize(values);\n\nexport function perc(pixels : number, percentage : number) : number {\n return Math.round((pixels * percentage) / 100);\n}\n\nexport function min(...args : $ReadOnlyArray) : number {\n return Math.min(...args);\n}\n\nexport function max(...args : $ReadOnlyArray) : number {\n return Math.max(...args);\n}\n\nexport function regexMap(str : string, regexp : RegExp, handler : () => T) : $ReadOnlyArray {\n const results = [];\n\n // $FlowFixMe\n str.replace(regexp, function regexMapMatcher(item) {\n results.push(handler ? handler.apply(null, arguments) : item);\n });\n\n // $FlowFixMe\n return results;\n}\n\nexport function svgToBase64(svg : string) : string {\n return `data:image/svg+xml;base64,${ base64encode(svg) }`;\n}\n\nexport function objFilter(obj : { [string] : T }, filter? : (T, ?string) => mixed = Boolean) : { [string] : R } {\n const result = {};\n\n for (const key in obj) {\n if (!obj.hasOwnProperty(key) || !filter(obj[key], key)) {\n continue;\n }\n\n result[key] = obj[key];\n }\n\n return result;\n}\n\nexport function identity (item : T) : T {\n return item;\n}\n\nexport function regexTokenize(text : string, regexp : RegExp) : $ReadOnlyArray {\n const result = [];\n text.replace(regexp, token => {\n result.push(token);\n return '';\n });\n return result;\n}\n\nexport function promiseDebounce(method : () => ZalgoPromise | T, delay : number = 50) : () => ZalgoPromise {\n\n let promise;\n let timeout;\n\n const promiseDebounced = function() : ZalgoPromise {\n if (timeout) {\n clearTimeout(timeout);\n }\n\n const localPromise = promise = promise || new ZalgoPromise();\n\n timeout = setTimeout(() => {\n promise = null;\n timeout = null;\n\n ZalgoPromise.try(method).then(\n result => { localPromise.resolve(result); },\n err => { localPromise.reject(err); }\n );\n }, delay);\n\n return localPromise;\n };\n\n return setFunctionName(promiseDebounced, `${ getFunctionName(method) }::promiseDebounced`);\n}\n\nexport function safeInterval(method : Function, time : number) : {| cancel : () => void |} {\n\n let timeout;\n\n function loop() {\n timeout = setTimeout(() => {\n method();\n loop();\n }, time);\n }\n\n loop();\n\n return {\n cancel() {\n clearTimeout(timeout);\n }\n };\n}\n\nexport function isInteger(str : string) : boolean {\n return Boolean(str.match(/^[0-9]+$/));\n}\n\nexport function isFloat(str : string) : boolean {\n return Boolean(str.match(/^[0-9]+\\.[0-9]+$/));\n}\n\nexport function serializePrimitive(value : string | number | boolean) : string {\n return value.toString();\n}\n\nexport function deserializePrimitive(value : string) : string | number | boolean {\n if (value === 'true') {\n return true;\n } else if (value === 'false') {\n return false;\n } else if (isInteger(value)) {\n return parseInt(value, 10);\n } else if (isFloat(value)) {\n return parseFloat(value);\n } else {\n return value;\n }\n}\n\nexport function dotify(obj : Object, prefix : string = '', newobj : Object = {}) : { [string] : string } {\n prefix = prefix ? `${ prefix }.` : prefix;\n for (const key in obj) {\n if (!obj.hasOwnProperty(key) || obj[key] === undefined || obj[key] === null || typeof obj[key] === 'function') {\n continue;\n } else if (obj[key] && Array.isArray(obj[key]) && obj[key].length && obj[key].every(val => typeof val !== 'object')) {\n newobj[`${ prefix }${ key }[]`] = obj[key].join(',');\n } else if (obj[key] && typeof obj[key] === 'object') {\n newobj = dotify(obj[key], `${ prefix }${ key }`, newobj);\n } else {\n newobj[`${ prefix }${ key }`] = serializePrimitive(obj[key]);\n }\n }\n return newobj;\n}\n\nexport function undotify(obj : { [string] : string }) : Object {\n \n const result = {};\n\n for (let key in obj) {\n if (!obj.hasOwnProperty(key) || typeof obj[key] !== 'string') {\n continue;\n }\n\n let value = obj[key];\n\n if (key.match(/^.+\\[\\]$/)) {\n key = key.slice(0, -2);\n value = value.split(',').map(deserializePrimitive);\n } else {\n value = deserializePrimitive(value);\n }\n\n let keyResult = result;\n const parts = key.split('.');\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n const isLast = (i + 1 === parts.length);\n const isIndex = !isLast && isInteger(parts[i + 1]);\n\n if (part === 'constructor' || part === 'prototype' || part === '__proto__') {\n throw new Error(`Disallowed key: ${ part }`);\n }\n\n if (isLast) {\n // $FlowFixMe\n keyResult[part] = value;\n } else {\n // $FlowFixMe\n keyResult = keyResult[part] = keyResult[part] || (isIndex ? [] : {});\n }\n }\n }\n\n return result;\n}\n\nexport type EventEmitterType = {|\n on : (eventName : string, handler : Function) => CancelableType,\n once : (eventName : string, handler : Function) => CancelableType,\n trigger : (eventName : string, ...args : $ReadOnlyArray) => ZalgoPromise,\n triggerOnce : (eventName : string, ...args : $ReadOnlyArray) => ZalgoPromise,\n reset : () => void\n|};\n\nexport function eventEmitter() : EventEmitterType {\n const triggered = {};\n let handlers = {};\n\n return {\n\n on(eventName : string, handler : Function) : CancelableType {\n const handlerList = handlers[eventName] = handlers[eventName] || [];\n\n handlerList.push(handler);\n\n let cancelled = false;\n\n return {\n cancel() {\n if (!cancelled) {\n cancelled = true;\n handlerList.splice(handlerList.indexOf(handler), 1);\n }\n\n }\n };\n },\n\n once(eventName : string, handler : Function) : CancelableType {\n\n const listener = this.on(eventName, () => {\n listener.cancel();\n handler();\n });\n\n return listener;\n },\n\n trigger(eventName : string, ...args : $ReadOnlyArray) : ZalgoPromise {\n\n const handlerList = handlers[eventName];\n const promises = [];\n\n if (handlerList) {\n for (const handler of handlerList) {\n promises.push(ZalgoPromise.try(() => handler(...args)));\n }\n }\n\n return ZalgoPromise.all(promises).then(noop);\n },\n\n triggerOnce(eventName : string, ...args : $ReadOnlyArray) : ZalgoPromise {\n\n if (triggered[eventName]) {\n return ZalgoPromise.resolve();\n }\n\n triggered[eventName] = true;\n return this.trigger(eventName, ...args);\n },\n\n reset() {\n handlers = {};\n }\n };\n}\n\nexport function camelToDasherize(string : string) : string {\n return string.replace(/([A-Z])/g, (g) => {\n return `-${ g.toLowerCase() }`;\n });\n}\n\nexport function dasherizeToCamel(string : string) : string {\n return string.replace(/-([a-z])/g, (g) => {\n return g[1].toUpperCase();\n });\n}\n\nexport function capitalizeFirstLetter(string : string) : string {\n return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();\n}\n\nexport function get(item : Object, path : string, def : mixed) : mixed {\n\n if (!path) {\n return def;\n }\n\n const pathParts = path.split('.');\n\n // Loop through each section of our key path\n\n for (let i = 0; i < pathParts.length; i++) {\n\n // If we have an object, we can get the key\n if (typeof item === 'object' && item !== null) {\n item = item[pathParts[i]];\n\n // Otherwise, we should return the default (undefined if not provided)\n } else {\n return def;\n }\n }\n\n // If our final result is undefined, we should return the default\n\n return item === undefined ? def : item;\n}\n\nexport function safeTimeout(method : Function, time : number) {\n\n const interval = safeInterval(() => {\n time -= 100;\n if (time <= 0) {\n interval.cancel();\n method();\n }\n }, 100);\n}\n\nexport function defineLazyProp(obj : Object | $ReadOnlyArray, key : string | number, getter : () => T) {\n if (Array.isArray(obj)) {\n if (typeof key !== 'number') {\n throw new TypeError(`Array key must be number`);\n }\n } else if (typeof obj === 'object' && obj !== null) {\n if (typeof key !== 'string') {\n throw new TypeError(`Object key must be string`);\n }\n }\n \n Object.defineProperty(obj, key, {\n configurable: true,\n enumerable: true,\n get: () => {\n // $FlowFixMe\n delete obj[key];\n const value = getter();\n // $FlowFixMe\n obj[key] = value;\n return value;\n },\n set: (value : T) => {\n // $FlowFixMe\n delete obj[key];\n // $FlowFixMe\n obj[key] = value;\n }\n });\n}\n\nexport function arrayFrom(item : Iterable) : $ReadOnlyArray { // eslint-disable-line no-undef\n return Array.prototype.slice.call(item);\n}\n\nexport function isObject(item : mixed) : boolean {\n return (typeof item === 'object' && item !== null);\n}\n\nexport function isObjectObject(obj : mixed) : boolean {\n return isObject(obj) && Object.prototype.toString.call(obj) === '[object Object]';\n}\n\nexport function isPlainObject(obj : mixed) : boolean {\n if (!isObjectObject(obj)) {\n return false;\n }\n\n // $FlowFixMe\n const constructor = obj.constructor;\n\n if (typeof constructor !== 'function') {\n return false;\n }\n\n const prototype = constructor.prototype;\n\n if (!isObjectObject(prototype)) {\n return false;\n }\n\n if (!prototype.hasOwnProperty('isPrototypeOf')) {\n return false;\n }\n\n return true;\n}\n\nexport function replaceObject | Object> (item : T, replacer : (mixed, string | number, string) => mixed, fullKey : string = '') : T {\n\n if (Array.isArray(item)) {\n const length = item.length;\n const result : Array = [];\n\n for (let i = 0; i < length; i++) {\n\n \n defineLazyProp(result, i, () => {\n const itemKey = fullKey ? `${ fullKey }.${ i }` : `${ i }`;\n const el = item[i];\n\n let child = replacer(el, i, itemKey);\n\n if (isPlainObject(child) || Array.isArray(child)) {\n // $FlowFixMe\n child = replaceObject(child, replacer, itemKey);\n }\n\n return child;\n });\n }\n\n // $FlowFixMe\n return result;\n } else if (isPlainObject(item)) {\n const result = {};\n\n for (const key in item) {\n if (!item.hasOwnProperty(key)) {\n continue;\n }\n\n defineLazyProp(result, key, () => {\n const itemKey = fullKey ? `${ fullKey }.${ key }` : `${ key }`;\n // $FlowFixMe\n const el = item[key];\n\n let child = replacer(el, key, itemKey);\n\n if (isPlainObject(child) || Array.isArray(child)) {\n // $FlowFixMe\n child = replaceObject(child, replacer, itemKey);\n }\n\n return child;\n });\n }\n\n // $FlowFixMe\n return result;\n } else {\n throw new Error(`Pass an object or array`);\n }\n}\n\n\nexport function copyProp(source : Object, target : Object, name : string, def : mixed) {\n if (source.hasOwnProperty(name)) {\n const descriptor = Object.getOwnPropertyDescriptor(source, name);\n // $FlowFixMe\n Object.defineProperty(target, name, descriptor);\n\n } else {\n target[name] = def;\n }\n}\n\ntype RegexResultType = {|\n text : string,\n groups : $ReadOnlyArray,\n start : number,\n end : number,\n length : number,\n replace : (text : string) => string\n|};\n\nexport function regex(pattern : string | RegExp, string : string, start : number = 0) : ?RegexResultType {\n\n if (typeof pattern === 'string') {\n // eslint-disable-next-line security/detect-non-literal-regexp\n pattern = new RegExp(pattern);\n }\n\n const result = string.slice(start).match(pattern);\n\n if (!result) {\n return;\n }\n\n // $FlowFixMe\n const index : number = result.index;\n const regmatch = result[0];\n\n return {\n text: regmatch,\n groups: result.slice(1),\n start: start + index,\n end: start + index + regmatch.length,\n length: regmatch.length,\n\n replace(text : string) : string {\n\n if (!regmatch) {\n return '';\n }\n\n return `${ regmatch.slice(0, start + index) }${ text }${ regmatch.slice(index + regmatch.length) }`;\n }\n };\n}\n\nexport function regexAll(pattern : string | RegExp, string : string) : $ReadOnlyArray {\n\n const matches = [];\n let start = 0;\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const regmatch = regex(pattern, string, start);\n\n if (!regmatch) {\n break;\n }\n\n matches.push(regmatch);\n start = match.end;\n }\n\n return matches;\n}\n\nexport function isDefined(value : ?mixed) : boolean {\n return value !== null && value !== undefined;\n}\n\nexport function cycle(method : Function) : ZalgoPromise {\n return ZalgoPromise.try(method).then(() => cycle(method));\n}\n\nexport function debounce(method : (...args : $ReadOnlyArray) => T, time : number = 100) : (...args : $ReadOnlyArray) => void {\n\n let timeout;\n\n const debounceWrapper = function() {\n clearTimeout(timeout);\n\n timeout = setTimeout(() => {\n return method.apply(this, arguments);\n }, time);\n };\n\n return setFunctionName(debounceWrapper, `${ getFunctionName(method) }::debounced`);\n}\n\nexport function isRegex(item : mixed) : boolean {\n return Object.prototype.toString.call(item) === '[object RegExp]';\n}\n\ntype FunctionProxy = (method : T) => T;\n\n// eslint-disable-next-line flowtype/no-weak-types\nexport const weakMapMemoize : FunctionProxy<*> = (method : (arg : any) => R) : ((...args : $ReadOnlyArray) => R) => {\n\n const weakmap = new WeakMap();\n\n // eslint-disable-next-line flowtype/no-weak-types\n return function weakmapMemoized(arg : any) : R {\n return weakmap.getOrSet(arg, () => method.call(this, arg));\n };\n};\n\ntype FunctionPromiseProxy) => ZalgoPromise> = (T) => T;\n\n// eslint-disable-next-line flowtype/no-weak-types\nexport const weakMapMemoizePromise : FunctionPromiseProxy<*, *> = (method : (arg : any) => ZalgoPromise) : ((...args : $ReadOnlyArray) => ZalgoPromise) => {\n\n const weakmap = new WeakMap();\n\n // eslint-disable-next-line flowtype/no-weak-types\n return function weakmapMemoizedPromise(arg : any) : ZalgoPromise {\n return weakmap.getOrSet(arg, () =>\n method.call(this, arg).finally(() => {\n weakmap.delete(arg);\n }));\n };\n};\n\nexport function getOrSet(obj : O, key : string, getter : () => T) : T {\n if (obj.hasOwnProperty(key)) {\n return obj[key];\n }\n\n const val = getter();\n obj[key] = val;\n return val;\n}\n\nexport type CleanupType = {|\n set : (string, T) => T, // eslint-disable-line no-undef\n register : (Function) => void,\n all : () => ZalgoPromise\n|};\n\nexport function cleanup(obj : Object) : CleanupType {\n\n const tasks = [];\n let cleaned = false;\n\n return {\n set(name : string, item : T) : T {\n if (!cleaned) {\n obj[name] = item;\n this.register(() => {\n delete obj[name];\n });\n }\n return item;\n },\n\n register(method : Function) {\n if (cleaned) {\n method();\n } else {\n tasks.push(once(method));\n }\n },\n\n all() : ZalgoPromise {\n const results = [];\n cleaned = true;\n\n while (tasks.length) {\n const task = tasks.shift();\n results.push(task());\n }\n\n return ZalgoPromise.all(results).then(noop);\n }\n };\n}\n\nexport function tryCatch(fn : () => T) : {| result : T, error : void |} | {| result : void, error : mixed |} {\n let result;\n let error;\n\n try {\n result = fn();\n } catch (err) {\n error = err;\n }\n \n // $FlowFixMe\n return { result, error };\n}\n\n// eslint-disable-next-line flowtype/no-mutable-array\nexport function removeFromArray>(arr : T, item : X) {\n const index = arr.indexOf(item);\n if (index !== -1) {\n arr.splice(index, 1);\n }\n}\n\nexport function assertExists(name : string, thing : void | null | T) : T {\n if (thing === null || typeof thing === 'undefined') {\n throw new Error(`Expected ${ name } to be present`);\n }\n \n return thing;\n}\n\nexport function unique(arr : $ReadOnlyArray) : $ReadOnlyArray {\n const result = {};\n for (const item of arr) {\n result[item] = true;\n }\n return Object.keys(result);\n}\n\nexport const constHas = (constant : T, value : X) : boolean => {\n return memoizedValues(constant).indexOf(value) !== -1;\n};\n\nexport function dedupeErrors(handler : (mixed) => T) : (mixed) => (T | void) {\n const seenErrors = [];\n const seenStringifiedErrors = {};\n\n return (err) => {\n if (seenErrors.indexOf(err) !== -1) {\n return;\n }\n\n seenErrors.push(err);\n\n const stringifiedError = stringifyError(err);\n if (seenStringifiedErrors[stringifiedError]) {\n return;\n }\n\n seenStringifiedErrors[stringifiedError] = true;\n return handler(err);\n };\n}\n\nexport class ExtendableError extends Error {\n constructor(message : string) {\n super(message);\n // eslint-disable-next-line unicorn/custom-error-definition\n this.name = this.constructor.name;\n if (typeof Error.captureStackTrace === 'function') {\n Error.captureStackTrace(this, this.constructor);\n } else {\n this.stack = (new Error(message)).stack;\n }\n }\n}\n \n","/* @flow */\n\nexport function hasNativeWeakMap() : boolean {\n\n if (typeof WeakMap === 'undefined') {\n return false;\n }\n\n if (typeof Object.freeze === 'undefined') {\n return false;\n }\n\n try {\n\n let testWeakMap = new WeakMap();\n let testKey = {};\n let testValue = '__testvalue__';\n\n Object.freeze(testKey);\n\n testWeakMap.set(testKey, testValue);\n\n if (testWeakMap.get(testKey) === testValue) {\n return true;\n }\n\n return false;\n\n } catch (err) {\n\n return false;\n }\n}\n","/* @flow */\n/* eslint max-lines: off */\n\nimport { ZalgoPromise } from 'zalgo-promise/src';\nimport { linkFrameWindow, isWindowClosed,\n type SameDomainWindowType, type CrossDomainWindowType } from 'cross-domain-utils/src';\nimport { WeakMap } from 'cross-domain-safe-weakmap/src';\n\nimport { inlineMemoize, memoize, noop, stringify, capitalizeFirstLetter,\n once, extend, safeInterval, uniqueID, arrayFrom, ExtendableError } from './util';\nimport { isDevice } from './device';\nimport { KEY_CODES, ATTRIBUTES } from './constants';\nimport type { CancelableType } from './types';\n\ntype ElementRefType = string | HTMLElement;\n\nexport function isDocumentReady() : boolean {\n return Boolean(document.body) && (document.readyState === 'complete');\n}\n\nexport function isDocumentInteractive() : boolean {\n return Boolean(document.body) && (document.readyState === 'interactive');\n}\n\nexport function urlEncode(str : string) : string {\n return str.replace(/\\?/g, '%3F').replace(/&/g, '%26').replace(/#/g, '%23').replace(/\\+/g, '%2B');\n}\n\nexport function waitForWindowReady() : ZalgoPromise {\n return inlineMemoize(waitForWindowReady, () : ZalgoPromise => {\n return new ZalgoPromise(resolve => {\n if (isDocumentReady()) {\n resolve();\n }\n\n window.addEventListener('load', () => resolve());\n });\n });\n}\n\ntype WaitForDocumentReady = () => ZalgoPromise;\n\nexport const waitForDocumentReady : WaitForDocumentReady = memoize(() => {\n return new ZalgoPromise(resolve => {\n\n if (isDocumentReady() || isDocumentInteractive()) {\n return resolve();\n }\n\n const interval = setInterval(() => {\n if (isDocumentReady() || isDocumentInteractive()) {\n clearInterval(interval);\n return resolve();\n }\n }, 10);\n });\n});\n\nexport function waitForDocumentBody() : ZalgoPromise {\n return ZalgoPromise.try(() => {\n if (document.body) {\n return document.body;\n }\n\n return waitForDocumentReady().then(() => {\n if (document.body) {\n return document.body;\n }\n\n throw new Error('Document ready but document.body not present');\n });\n });\n}\n\nexport function parseQuery(queryString : string) : Object {\n return inlineMemoize(parseQuery, () : Object => {\n const params = {};\n\n if (!queryString) {\n return params;\n }\n\n if (queryString.indexOf('=') === -1) {\n return params;\n }\n\n for (let pair of queryString.split('&')) {\n pair = pair.split('=');\n\n if (pair[0] && pair[1]) {\n params[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);\n }\n }\n\n return params;\n }, [ queryString ]);\n}\n\n\nexport function getQueryParam(name : string) : string {\n return parseQuery(window.location.search.slice(1))[name];\n}\n\nexport function urlWillRedirectPage(url : string) : boolean {\n\n if (url.indexOf('#') === -1) {\n return true;\n }\n\n if (url.indexOf('#') === 0) {\n return false;\n }\n\n if (url.split('#')[0] === window.location.href.split('#')[0]) {\n return false;\n }\n\n return true;\n}\n\nexport function formatQuery(obj : { [ string ] : string } = {}) : string {\n\n return Object.keys(obj).filter(key => {\n return typeof obj[key] === 'string';\n }).map(key => {\n return `${ urlEncode(key) }=${ urlEncode(obj[key]) }`;\n }).join('&');\n}\n\nexport function extendQuery(originalQuery : string, props : { [ string ] : string } = {}) : string {\n\n if (!props || !Object.keys(props).length) {\n return originalQuery;\n }\n\n return formatQuery({\n ...parseQuery(originalQuery),\n ...props\n });\n}\n\nexport function extendUrl(url : string, options : {| query? : { [string] : string }, hash? : { [string] : string } |}) : string {\n\n const query = options.query || {};\n const hash = options.hash || {};\n\n let originalUrl;\n let originalQuery;\n let originalHash;\n\n [ originalUrl, originalHash ] = url.split('#');\n [ originalUrl, originalQuery ] = originalUrl.split('?');\n\n const queryString = extendQuery(originalQuery, query);\n const hashString = extendQuery(originalHash, hash);\n\n if (queryString) {\n originalUrl = `${ originalUrl }?${ queryString }`;\n }\n\n if (hashString) {\n originalUrl = `${ originalUrl }#${ hashString }`;\n }\n\n return originalUrl;\n}\n\nexport function redirect(url : string, win : CrossDomainWindowType = window) : ZalgoPromise {\n return new ZalgoPromise(resolve => {\n win.location = url;\n if (!urlWillRedirectPage(url)) {\n resolve();\n }\n });\n}\n\nexport function hasMetaViewPort() : boolean {\n const meta = document.querySelector('meta[name=viewport]');\n\n if (isDevice() && window.screen.width < 660 && !meta) {\n return false;\n }\n\n return true;\n}\n\nexport function isElementVisible(el : HTMLElement) : boolean {\n return Boolean(el.offsetWidth || el.offsetHeight || el.getClientRects().length);\n}\n\nexport function getPerformance() : ?Performance {\n return inlineMemoize(getPerformance, () : ?Performance => {\n const performance = window.performance;\n\n if (\n performance &&\n performance.now &&\n performance.timing &&\n performance.timing.connectEnd &&\n performance.timing.navigationStart &&\n (Math.abs(performance.now() - Date.now()) > 1000) &&\n (performance.now() - (performance.timing.connectEnd - performance.timing.navigationStart)) > 0\n ) {\n return performance;\n }\n });\n}\n\nexport function enablePerformance() : boolean {\n return Boolean(getPerformance());\n}\n\nexport function getPageRenderTime() : ZalgoPromise {\n return waitForDocumentReady().then(() => {\n const performance = getPerformance();\n\n if (!performance) {\n return;\n }\n \n const timing = performance.timing;\n\n if (timing.connectEnd && timing.domInteractive) {\n return timing.domInteractive - timing.connectEnd;\n }\n });\n}\n\nexport function htmlEncode(html : string = '') : string {\n return html.toString()\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n .replace(/\\//g, '/');\n}\n\nexport function isBrowser() : boolean {\n return (typeof window !== 'undefined');\n}\n\nexport function querySelectorAll(selector : string, doc : HTMLElement = window.document) : $ReadOnlyArray {\n return Array.prototype.slice.call(doc.querySelectorAll(selector));\n}\n\nexport function onClick(element : HTMLElement, handler : (Event) => void) {\n element.addEventListener('touchstart', noop);\n element.addEventListener('click', handler);\n element.addEventListener('keypress', (event : Event) => {\n // $FlowFixMe\n if (event.keyCode === KEY_CODES.ENTER || event.keyCode === KEY_CODES.SPACE) { // eslint-disable-line unicorn/prefer-event-key\n return handler(event);\n }\n });\n}\n\nexport function getScript({ host = window.location.host, path, reverse = false } : {| host? : string, path : string, reverse? : boolean |}) : ?HTMLScriptElement {\n return inlineMemoize(getScript, () : ?HTMLScriptElement => {\n\n const url = `${ host }${ path }`;\n const scripts = Array.prototype.slice.call(document.getElementsByTagName('script'));\n\n if (reverse) {\n scripts.reverse();\n }\n\n for (const script of scripts) {\n if (!script.src) {\n continue;\n }\n\n const src = script.src.replace(/^https?:\\/\\//, '').split('?')[0];\n\n if (src === url) {\n return script;\n }\n }\n }, [ path ]);\n}\n\nexport function isLocalStorageEnabled() : boolean {\n return inlineMemoize(isLocalStorageEnabled, () => {\n try {\n if (typeof window === 'undefined') {\n return false;\n }\n\n if (window.localStorage) {\n const value = Math.random().toString();\n window.localStorage.setItem('__test__localStorage__', value);\n const result = window.localStorage.getItem('__test__localStorage__');\n window.localStorage.removeItem('__test__localStorage__');\n if (value === result) {\n return true;\n }\n }\n } catch (err) {\n // pass\n }\n return false;\n });\n}\n\nexport function getBrowserLocales() : $ReadOnlyArray<{| country? : string, lang : string |}> {\n const nav = window.navigator; // eslint-disable-line compat/compat\n\n const locales = nav.languages\n ? [ ...nav.languages ]\n : [];\n\n if (nav.language) {\n locales.push(nav.language);\n }\n\n if (nav.userLanguage) {\n locales.push(nav.userLanguage);\n }\n\n return locales.map(locale => {\n\n if (locale && locale.match(/^[a-z]{2}[-_][A-Z]{2}$/)) {\n const [ lang, country ] = locale.split(/[-_]/);\n return { country, lang };\n }\n\n if (locale && locale.match(/^[a-z]{2}$/)) {\n return { lang: locale };\n }\n\n return null;\n\n }).filter(Boolean);\n}\n\n\nexport function appendChild(container : HTMLElement, child : HTMLElement | Text) {\n container.appendChild(child);\n}\n\nexport function isElement(element : mixed) : boolean {\n\n if (element instanceof window.Element) {\n return true;\n }\n\n if (element !== null && typeof element === 'object' && element.nodeType === 1 && typeof element.style === 'object' && typeof element.ownerDocument === 'object') {\n return true;\n }\n\n return false;\n}\n\nexport function getElementSafe(id : ElementRefType, doc : Document | HTMLElement = document) : ?HTMLElement {\n\n if (isElement(id)) {\n // $FlowFixMe\n return id;\n }\n\n if (typeof id === 'string') {\n return doc.querySelector(id);\n }\n}\n\nexport function getElement(id : ElementRefType, doc : Document | HTMLElement = document) : HTMLElement {\n\n const element = getElementSafe(id, doc);\n\n if (element) {\n return element;\n }\n\n throw new Error(`Can not find element: ${ stringify(id) }`);\n}\n\nexport function elementReady(id : ElementRefType) : ZalgoPromise {\n return new ZalgoPromise((resolve, reject) => {\n\n const name = stringify(id);\n let el = getElementSafe(id);\n\n if (el) {\n return resolve(el);\n }\n\n if (isDocumentReady()) {\n return reject(new Error(`Document is ready and element ${ name } does not exist`));\n }\n\n const interval = setInterval(() => {\n\n el = getElementSafe(id);\n\n if (el) {\n clearInterval(interval);\n return resolve(el);\n }\n\n if (isDocumentReady()) {\n clearInterval(interval);\n return reject(new Error(`Document is ready and element ${ name } does not exist`));\n }\n }, 10);\n });\n}\n\n// eslint-disable-next-line unicorn/custom-error-definition\nexport class PopupOpenError extends ExtendableError {}\n\ntype PopupOptions = {|\n name? : string,\n width? : number,\n height? : number,\n top? : number,\n left? : number,\n status? : 0 | 1,\n resizable? : 0 | 1,\n toolbar? : 0 | 1,\n menubar? : 0 | 1,\n scrollbars? : 0 | 1\n|};\n\nexport function popup(url : string, options? : PopupOptions) : CrossDomainWindowType {\n\n // $FlowFixMe\n options = options || {};\n\n const { width, height } = options;\n\n let top = 0;\n let left = 0;\n\n if (width) {\n if (window.outerWidth) {\n left = Math.round((window.outerWidth - width) / 2) + window.screenX;\n } else if (window.screen.width) {\n left = Math.round((window.screen.width - width) / 2);\n }\n }\n\n if (height) {\n if (window.outerHeight) {\n top = Math.round((window.outerHeight - height) / 2) + window.screenY;\n } else if (window.screen.height) {\n top = Math.round((window.screen.height - height) / 2);\n }\n }\n\n if (width && height) {\n // $FlowFixMe\n options = {\n top,\n left,\n width,\n height,\n status: 1,\n toolbar: 0,\n menubar: 0,\n resizable: 1,\n scrollbars: 1,\n ...options\n };\n }\n\n const name = options.name || '';\n delete options.name;\n\n // eslint-disable-next-line array-callback-return\n const params = Object.keys(options).map(key => {\n // $FlowFixMe\n if (options[key] !== null && options[key] !== undefined) {\n return `${ key }=${ stringify(options[key]) }`;\n }\n }).filter(Boolean).join(',');\n\n let win;\n\n try {\n win = window.open(url, name, params, true);\n } catch (err) {\n throw new PopupOpenError(`Can not open popup window - ${ err.stack || err.message }`);\n }\n\n if (isWindowClosed(win)) {\n const err = new PopupOpenError(`Can not open popup window - blocked`);\n throw err;\n }\n\n window.addEventListener('unload', () => win.close());\n\n return win;\n}\n\n\nexport function writeToWindow(win : SameDomainWindowType, html : string) {\n try {\n win.document.open();\n win.document.write(html);\n win.document.close();\n } catch (err) {\n try {\n win.location = `javascript: document.open(); document.write(${ JSON.stringify(html) }); document.close();`;\n } catch (err2) {\n // pass\n }\n }\n}\n\nexport function writeElementToWindow(win : SameDomainWindowType, el : HTMLElement) {\n\n const tag = el.tagName.toLowerCase();\n\n if (tag !== 'html') {\n throw new Error(`Expected element to be html, got ${ tag }`);\n }\n\n const documentElement = win.document.documentElement;\n\n for (const child of arrayFrom(documentElement.children)) {\n documentElement.removeChild(child);\n }\n\n for (const child of arrayFrom(el.children)) {\n documentElement.appendChild(child);\n }\n}\n\nexport function setStyle(el : HTMLElement, styleText : string, doc : Document = window.document) {\n // $FlowFixMe\n if (el.styleSheet) {\n // $FlowFixMe\n el.styleSheet.cssText = styleText;\n } else {\n el.appendChild(doc.createTextNode(styleText));\n }\n}\n\nexport type ElementOptionsType = {|\n style? : { [ string ] : string },\n id? : string,\n class? : ?$ReadOnlyArray,\n attributes? : { [ string ] : string },\n styleSheet? : ?string,\n html? : ?string\n|};\n\nlet awaitFrameLoadPromises : WeakMap>;\n\nexport function awaitFrameLoad(frame : HTMLIFrameElement) : ZalgoPromise {\n awaitFrameLoadPromises = awaitFrameLoadPromises || new WeakMap();\n\n if (awaitFrameLoadPromises.has(frame)) {\n const promise = awaitFrameLoadPromises.get(frame);\n if (promise) {\n return promise;\n }\n }\n\n const promise = new ZalgoPromise((resolve, reject) => {\n frame.addEventListener('load', () => {\n linkFrameWindow(frame);\n resolve(frame);\n });\n\n frame.addEventListener('error', (err : Event) => {\n if (frame.contentWindow) {\n resolve(frame);\n } else {\n reject(err);\n }\n });\n });\n\n awaitFrameLoadPromises.set(frame, promise);\n\n return promise;\n}\n\nexport function awaitFrameWindow(frame : HTMLIFrameElement) : ZalgoPromise {\n return awaitFrameLoad(frame).then(loadedFrame => {\n\n if (!loadedFrame.contentWindow) {\n throw new Error(`Could not find window in iframe`);\n }\n\n return loadedFrame.contentWindow;\n });\n}\n\nconst getDefaultCreateElementOptions = () : ElementOptionsType => {\n // $FlowFixMe\n return {};\n};\n\nexport function createElement(tag : string = 'div', options : ElementOptionsType = getDefaultCreateElementOptions(), container : ?HTMLElement) : HTMLElement {\n\n tag = tag.toLowerCase();\n const element = document.createElement(tag);\n\n if (options.style) {\n extend(element.style, options.style);\n }\n\n if (options.class) {\n element.className = options.class.join(' ');\n }\n\n if (options.id) {\n element.setAttribute('id', options.id);\n }\n\n if (options.attributes) {\n for (const key of Object.keys(options.attributes)) {\n element.setAttribute(key, options.attributes[key]);\n }\n }\n\n if (options.styleSheet) {\n setStyle(element, options.styleSheet);\n }\n\n if (container) {\n appendChild(container, element);\n }\n\n if (options.html) {\n if (tag === 'iframe') {\n // $FlowFixMe\n if (!container || !element.contentWindow) {\n throw new Error(`Iframe html can not be written unless container provided and iframe in DOM`);\n }\n\n // $FlowFixMe\n writeToWindow(element.contentWindow, options.html);\n\n } else {\n element.innerHTML = options.html;\n }\n }\n\n return element;\n}\n\ntype StringMap = {|\n [ string ] : string\n|};\n\nexport type IframeElementOptionsType = {|\n style? : StringMap,\n class? : ?$ReadOnlyArray,\n attributes? : StringMap,\n styleSheet? : ?string,\n html? : ?string,\n url? : ?string\n|};\n\nconst getDefaultIframeOptions = () : IframeElementOptionsType => {\n // $FlowFixMe\n return {};\n};\n\nconst getDefaultStringMap = () : StringMap => {\n // $FlowFixMe\n return {};\n};\n\nexport function iframe(options : IframeElementOptionsType = getDefaultIframeOptions(), container : ?HTMLElement) : HTMLIFrameElement {\n\n const attributes = options.attributes || getDefaultStringMap();\n const style = options.style || getDefaultStringMap();\n\n // $FlowFixMe\n const newAttributes = {\n allowTransparency: 'true',\n ...attributes\n };\n\n // $FlowFixMe\n const newStyle = {\n backgroundColor: 'transparent',\n border: 'none',\n ...style\n };\n\n const frame = createElement('iframe', {\n attributes: newAttributes,\n style: newStyle,\n html: options.html,\n class: options.class\n });\n\n const isIE = window.navigator.userAgent.match(/MSIE|Edge/i); // eslint-disable-line compat/compat\n\n if (!frame.hasAttribute('id')) {\n frame.setAttribute('id', uniqueID());\n }\n\n // $FlowFixMe\n awaitFrameLoad(frame);\n\n if (container) {\n const el = getElement(container);\n el.appendChild(frame);\n }\n\n if (options.url || isIE) {\n frame.setAttribute('src', options.url || 'about:blank');\n }\n\n // $FlowFixMe\n return frame;\n}\n\nexport function addEventListener(obj : HTMLElement, event : string, handler : (event : Event) => void) : CancelableType {\n obj.addEventListener(event, handler);\n return {\n cancel() {\n obj.removeEventListener(event, handler);\n }\n };\n}\n\nexport function bindEvents(element : HTMLElement, eventNames : $ReadOnlyArray, handler : (event : Event) => void) : CancelableType {\n\n handler = once(handler);\n\n for (const eventName of eventNames) {\n element.addEventListener(eventName, handler);\n }\n\n return {\n cancel: once(() => {\n for (const eventName of eventNames) {\n element.removeEventListener(eventName, handler);\n }\n })\n };\n}\n\nconst VENDOR_PREFIXES = [ 'webkit', 'moz', 'ms', 'o' ];\n\nexport function setVendorCSS(element : HTMLElement, name : string, value : string) {\n\n // $FlowFixMe\n element.style[name] = value;\n\n const capitalizedName = capitalizeFirstLetter(name);\n\n for (const prefix of VENDOR_PREFIXES) {\n // $FlowFixMe\n element.style[`${ prefix }${ capitalizedName }`] = value;\n }\n}\n\nconst ANIMATION_START_EVENTS = [ 'animationstart', 'webkitAnimationStart', 'oAnimationStart', 'MSAnimationStart' ];\nconst ANIMATION_END_EVENTS = [ 'animationend', 'webkitAnimationEnd', 'oAnimationEnd', 'MSAnimationEnd' ];\n\nexport function animate(element : ElementRefType, name : string, clean : (Function) => void, timeout : number = 1000) : ZalgoPromise {\n return new ZalgoPromise((resolve, reject) => {\n\n const el = getElement(element);\n\n if (!el) {\n return resolve();\n }\n\n let hasStarted = false;\n\n // eslint-disable-next-line prefer-const\n let startTimeout;\n let endTimeout;\n // eslint-disable-next-line prefer-const\n let startEvent;\n // eslint-disable-next-line prefer-const\n let endEvent;\n\n function cleanUp() {\n clearTimeout(startTimeout);\n clearTimeout(endTimeout);\n startEvent.cancel();\n endEvent.cancel();\n }\n\n startEvent = bindEvents(el, ANIMATION_START_EVENTS, event => {\n\n // $FlowFixMe\n if (event.target !== el || event.animationName !== name) {\n return;\n }\n\n clearTimeout(startTimeout);\n\n event.stopPropagation();\n\n startEvent.cancel();\n hasStarted = true;\n\n endTimeout = setTimeout(() => {\n cleanUp();\n resolve();\n }, timeout);\n });\n\n endEvent = bindEvents(el, ANIMATION_END_EVENTS, event => {\n\n // $FlowFixMe\n if (event.target !== el || event.animationName !== name) {\n return;\n }\n\n cleanUp();\n\n // $FlowFixMe\n if (typeof event.animationName === 'string' && event.animationName !== name) {\n return reject(`Expected animation name to be ${ name }, found ${ event.animationName }`);\n }\n\n return resolve();\n });\n\n setVendorCSS(el, 'animationName', name);\n\n startTimeout = setTimeout(() => {\n if (!hasStarted) {\n cleanUp();\n return resolve();\n }\n }, 200);\n\n if (clean) {\n clean(cleanUp);\n }\n });\n}\n\nexport function makeElementVisible(element : HTMLElement) {\n element.style.setProperty('visibility', '');\n}\n\nexport function makeElementInvisible(element : HTMLElement) {\n element.style.setProperty('visibility', 'hidden', 'important');\n}\n\n\nexport function showElement(element : HTMLElement) {\n element.style.setProperty('display', '');\n}\n\nexport function hideElement(element : HTMLElement) {\n element.style.setProperty('display', 'none', 'important');\n}\n\nexport function destroyElement(element : HTMLElement) {\n if (element && element.parentNode) {\n element.parentNode.removeChild(element);\n }\n}\n\nexport function showAndAnimate(element : HTMLElement, name : string, clean : (Function) => void) : ZalgoPromise {\n const animation = animate(element, name, clean);\n showElement(element);\n return animation;\n}\n\nexport function animateAndHide(element : HTMLElement, name : string, clean : (Function) => void) : ZalgoPromise {\n return animate(element, name, clean).then(() => {\n hideElement(element);\n });\n}\n\nexport function addClass(element : HTMLElement, name : string) {\n element.classList.add(name);\n}\n\nexport function removeClass(element : HTMLElement, name : string) {\n element.classList.remove(name);\n}\n\nexport function isElementClosed(el : HTMLElement) : boolean {\n if (!el || !el.parentNode) {\n return true;\n }\n return false;\n}\n\nexport function watchElementForClose(element : HTMLElement, handler : () => mixed) : CancelableType {\n handler = once(handler);\n\n let interval;\n\n if (isElementClosed(element)) {\n handler();\n } else {\n interval = safeInterval(() => {\n if (isElementClosed(element)) {\n interval.cancel();\n handler();\n }\n }, 50);\n }\n\n return {\n cancel() {\n if (interval) {\n interval.cancel();\n }\n }\n };\n}\n\nexport function fixScripts(el : HTMLElement, doc : Document = window.document) {\n for (const script of querySelectorAll('script', el)) {\n const parentNode = script.parentNode;\n\n if (!parentNode) {\n continue;\n }\n\n const newScript = doc.createElement('script');\n newScript.text = script.textContent;\n parentNode.replaceChild(newScript, script);\n }\n}\n\ntype OnResizeOptions = {|\n width? : boolean,\n height? : boolean,\n interval? : number,\n win? : SameDomainWindowType\n|};\n\nexport function onResize(el : HTMLElement, handler : ({| width : number, height : number |}) => void, { width = true, height = true, interval = 100, win = window } : OnResizeOptions = {}) : {| cancel : () => void |} {\n let currentWidth = el.offsetWidth;\n let currentHeight = el.offsetHeight;\n let canceled = false;\n\n handler({ width: currentWidth, height: currentHeight });\n\n const check = () => {\n if (canceled || !isElementVisible(el)) {\n return;\n }\n\n const newWidth = el.offsetWidth;\n const newHeight = el.offsetHeight;\n\n if ((width && newWidth !== currentWidth) || (height && newHeight !== currentHeight)) {\n handler({ width: newWidth, height: newHeight });\n }\n\n currentWidth = newWidth;\n currentHeight = newHeight;\n };\n\n let observer;\n let timeout;\n\n win.addEventListener('resize', check);\n \n if (typeof win.ResizeObserver !== 'undefined') {\n observer = new win.ResizeObserver(check);\n observer.observe(el);\n timeout = safeInterval(check, interval * 10);\n\n } else if (typeof win.MutationObserver !== 'undefined') {\n observer = new win.MutationObserver(check);\n observer.observe(el, {\n attributes: true,\n childList: true,\n subtree: true,\n characterData: false\n });\n timeout = safeInterval(check, interval * 10);\n } else {\n timeout = safeInterval(check, interval);\n }\n\n return {\n cancel: () => {\n canceled = true;\n observer.disconnect();\n window.removeEventListener('resize', check);\n timeout.cancel();\n }\n };\n}\n\nexport function getResourceLoadTime(url : string) : ?number {\n const performance = getPerformance();\n\n if (!performance) {\n return;\n }\n\n if (typeof performance.getEntries !== 'function') {\n return;\n }\n\n const entries = performance.getEntries();\n\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n\n if (entry && entry.name && entry.name.indexOf(url) === 0 && typeof entry.duration === 'number') {\n return Math.floor(entry.duration);\n }\n }\n}\n\nexport function isShadowElement(element : Node) : boolean {\n while (element.parentNode) {\n element = element.parentNode;\n }\n\n return element.toString() === '[object ShadowRoot]';\n}\n\nexport function getShadowRoot(element : Node) : ?Node {\n while (element.parentNode) {\n element = element.parentNode;\n }\n\n if (isShadowElement(element)) {\n return element;\n }\n}\n\nexport function getShadowHost(element : Node) : ?HTMLElement {\n const shadowRoot = getShadowRoot(element);\n\n // $FlowFixMe\n if (shadowRoot.host) {\n // $FlowFixMe\n return shadowRoot.host;\n }\n}\n\nexport function insertShadowSlot(element : HTMLElement) : HTMLElement {\n const shadowHost = getShadowHost(element);\n\n if (!shadowHost) {\n throw new Error(`Element is not in shadow dom`);\n }\n\n if (isShadowElement(shadowHost)) {\n throw new Error(`Host element is also in shadow dom`);\n }\n\n const slotName = `shadow-slot-${ uniqueID() }`;\n\n const slot = document.createElement('slot');\n slot.setAttribute('name', slotName);\n element.appendChild(slot);\n \n const slotProvider = document.createElement('div');\n slotProvider.setAttribute('slot', slotName);\n shadowHost.appendChild(slotProvider);\n\n return slotProvider;\n}\n\nexport function preventClickFocus(el : HTMLElement) {\n const onFocus = (event : Event) => {\n el.removeEventListener('focus', onFocus);\n event.preventDefault();\n el.blur();\n return false;\n };\n\n el.addEventListener('mousedown', () => {\n el.addEventListener('focus', onFocus);\n setTimeout(() => {\n el.removeEventListener('focus', onFocus);\n }, 1);\n });\n}\n\nexport function getStackTrace() : string {\n try {\n throw new Error('_');\n }\n catch (err) {\n return err.stack || '';\n }\n}\n\nfunction inferCurrentScript() : ?HTMLScriptElement {\n try {\n const stack = getStackTrace();\n const stackDetails = (/.*at [^(]*\\((.*):(.+):(.+)\\)$/ig).exec(stack);\n const scriptLocation = stackDetails && stackDetails[1];\n\n if (!scriptLocation) {\n return;\n }\n\n for (const script of Array.prototype.slice.call(document.getElementsByTagName('script')).reverse()) {\n if (script.src && script.src === scriptLocation) {\n return script;\n }\n }\n\n } catch (err) {\n // pass\n }\n}\n\n// eslint-disable-next-line compat/compat\nlet currentScript = typeof document !== 'undefined' ? document.currentScript : null;\n\ntype GetCurrentScript = () => HTMLScriptElement;\n\nexport const getCurrentScript : GetCurrentScript = memoize(() => {\n if (currentScript) {\n return currentScript;\n }\n\n currentScript = inferCurrentScript();\n\n if (currentScript) {\n return currentScript;\n }\n\n throw new Error('Can not determine current script');\n});\n\nconst currentUID = uniqueID();\n\ntype GetCurrentScriptUID = () => string;\n\nexport const getCurrentScriptUID : GetCurrentScriptUID = memoize(() => {\n let script;\n\n try {\n script = getCurrentScript();\n } catch (err) {\n return currentUID;\n }\n\n let uid = script.getAttribute(ATTRIBUTES.UID);\n\n if (uid && typeof uid === 'string') {\n return uid;\n }\n\n uid = uniqueID();\n script.setAttribute(ATTRIBUTES.UID, uid);\n\n return uid;\n});\n","/* @flow */\n\nexport const KEY_CODES = {\n ENTER: 13,\n SPACE: 32\n};\n\nexport const ATTRIBUTES = {\n UID: 'data-uid'\n};\n","/* @flow */\n\nimport { ZalgoPromise } from 'zalgo-promise/src';\nimport { type SameDomainWindowType } from 'cross-domain-utils/src';\n\ntype RequestOptionsType = {|\n url : string,\n method? : string,\n headers? : { [key : string] : string },\n json? : $ReadOnlyArray | Object,\n data? : { [key : string] : string },\n body? : string,\n win? : SameDomainWindowType,\n timeout? : number\n|};\n\ntype ResponseType = {|\n status : number,\n headers : { [string] : string },\n body : Object\n|};\n\nconst HEADERS = {\n CONTENT_TYPE: 'content-type',\n ACCEPT: 'accept'\n};\n\nconst headerBuilders = [];\n\nfunction parseHeaders(rawHeaders : string = '') : { [string] : string } {\n const result = {};\n for (const line of rawHeaders.trim().split('\\n')) {\n const [ key, ...values ] = line.split(':');\n result[key.toLowerCase()] = values.join(':').trim();\n }\n return result;\n}\n\nexport function request({ url, method = 'get', headers = {}, json, data, body, win = window, timeout = 0 } : RequestOptionsType) : ZalgoPromise {\n return new ZalgoPromise((resolve, reject) => {\n\n if ((json && data) || (json && body) || (data && json)) {\n throw new Error(`Only options.json or options.data or options.body should be passed`);\n }\n\n const normalizedHeaders = {};\n\n for (const key of Object.keys(headers)) {\n normalizedHeaders[key.toLowerCase()] = headers[key];\n }\n\n if (json) {\n normalizedHeaders[HEADERS.CONTENT_TYPE] = normalizedHeaders[HEADERS.CONTENT_TYPE] || 'application/json';\n } else if (data || body) {\n normalizedHeaders[HEADERS.CONTENT_TYPE] = normalizedHeaders[HEADERS.CONTENT_TYPE] || 'application/x-www-form-urlencoded; charset=utf-8';\n }\n\n normalizedHeaders[HEADERS.ACCEPT] = normalizedHeaders[HEADERS.ACCEPT] || 'application/json';\n\n for (const headerBuilder of headerBuilders) {\n const builtHeaders = headerBuilder();\n\n for (const key of Object.keys(builtHeaders)) {\n normalizedHeaders[key.toLowerCase()] = builtHeaders[key];\n }\n }\n\n const xhr = new win.XMLHttpRequest();\n\n xhr.addEventListener('load', function xhrLoad() : void {\n\n const responseHeaders = parseHeaders(this.getAllResponseHeaders());\n\n if (!this.status) {\n return reject(new Error(`Request to ${ method.toLowerCase() } ${ url } failed: no response status code.`));\n }\n \n const contentType = responseHeaders['content-type'];\n const isJSON = contentType && (contentType.indexOf('application/json') === 0 || contentType.indexOf('text/json') === 0);\n let responseBody = this.responseText;\n\n try {\n responseBody = JSON.parse(responseBody);\n } catch (err) {\n if (isJSON) {\n return reject(new Error(`Invalid json: ${ this.responseText }.`));\n }\n }\n\n const res = {\n status: this.status,\n headers: responseHeaders,\n body: responseBody\n };\n\n return resolve(res);\n\n }, false);\n\n xhr.addEventListener('error', (evt) => {\n reject(new Error(`Request to ${ method.toLowerCase() } ${ url } failed: ${ evt.toString() }.`));\n }, false);\n\n xhr.open(method, url, true);\n\n for (const key in normalizedHeaders) {\n if (normalizedHeaders.hasOwnProperty(key)) {\n xhr.setRequestHeader(key, normalizedHeaders[key]);\n }\n }\n\n if (json) {\n body = JSON.stringify(json);\n } else if (data) {\n body = Object.keys(data).map(key => {\n return `${ encodeURIComponent(key) }=${ data ? encodeURIComponent(data[key]) : '' }`;\n }).join('&');\n }\n\n xhr.timeout = timeout;\n xhr.ontimeout = function xhrTimeout() {\n reject(new Error(`Request to ${ method.toLowerCase() } ${ url } has timed out`));\n };\n\n xhr.send(body);\n });\n}\n\nexport function addHeaderBuilder(method : () => { [string] : string }) {\n headerBuilders.push(method);\n}\n","/* @flow */\n\nexport const LOG_LEVEL = {\n DEBUG: ('debug' : 'debug'),\n INFO: ('info' : 'info'),\n WARN: ('warn' : 'warn'),\n ERROR: ('error' : 'error')\n};\n\nexport const PROTOCOL = {\n FILE: 'file:'\n};\n","/* @flow */\n\nimport { LOG_LEVEL } from './constants';\n\nexport const AUTO_FLUSH_LEVEL = [ LOG_LEVEL.WARN, LOG_LEVEL.ERROR ];\n\nexport const LOG_LEVEL_PRIORITY = [ LOG_LEVEL.ERROR, LOG_LEVEL.WARN, LOG_LEVEL.INFO, LOG_LEVEL.DEBUG ];\n\nexport const FLUSH_INTERVAL = 60 * 1000;\n\nexport const DEFAULT_LOG_LEVEL : $Values = __DEBUG__ ? LOG_LEVEL.DEBUG : LOG_LEVEL.WARN;\n","/* @flow */\n\nimport { ZalgoPromise } from 'zalgo-promise/src';\nimport { request, isBrowser, promiseDebounce, noop, safeInterval, objFilter } from 'belter/src';\n\nimport { DEFAULT_LOG_LEVEL, LOG_LEVEL_PRIORITY, AUTO_FLUSH_LEVEL, FLUSH_INTERVAL } from './config';\nimport { LOG_LEVEL, PROTOCOL } from './constants';\n\ntype TransportOptions = {|\n url : string,\n method : string,\n headers : { [string] : string },\n json : Object,\n enableSendBeacon : boolean\n|};\n\ntype Payload = { [string] : string | boolean };\ntype Transport = (TransportOptions) => ZalgoPromise;\n\ntype LoggerOptions = {|\n url : string,\n prefix? : string,\n logLevel? : $Values,\n transport? : Transport,\n flushInterval? : number,\n enableSendBeacon? : boolean\n|};\n\ntype ClientPayload = { [string] : ?string | ?boolean };\ntype Log = (name : string, payload? : ClientPayload) => LoggerType; // eslint-disable-line no-use-before-define\ntype Track = (payload : ClientPayload) => LoggerType; // eslint-disable-line no-use-before-define\n\ntype Builder = (Payload) => ClientPayload;\ntype AddBuilder = (Builder) => LoggerType; // eslint-disable-line no-use-before-define\n\nexport type LoggerType = {|\n debug : Log,\n info : Log,\n warn : Log,\n error : Log,\n\n track : Track,\n\n flush : () => ZalgoPromise,\n immediateFlush : () => ZalgoPromise,\n\n addPayloadBuilder : AddBuilder,\n addMetaBuilder : AddBuilder,\n addTrackingBuilder : AddBuilder,\n addHeaderBuilder : AddBuilder,\n\n setTransport : (Transport) => LoggerType\n|};\n\nfunction httpTransport({ url, method, headers, json, enableSendBeacon = false } : TransportOptions) : ZalgoPromise {\n const hasHeaders = headers && Object.keys(headers).length;\n if (window && window.navigator.sendBeacon && !hasHeaders && enableSendBeacon && window.Blob) {\n return new ZalgoPromise(resolve => {\n const blob = new Blob([ JSON.stringify(json) ], { type: 'application/json' });\n resolve(window.navigator.sendBeacon(url, blob));\n });\n } else {\n return request({ url, method, headers, json }).then(noop);\n }\n}\n\nfunction extendIfDefined(target : { [string] : string | boolean }, source : { [string] : ?string | ?boolean }) {\n for (const key in source) {\n if (source.hasOwnProperty(key) && source[key] && !target[key]) {\n target[key] = source[key];\n }\n }\n}\n\nexport function Logger({ url, prefix, logLevel = DEFAULT_LOG_LEVEL, transport = httpTransport, flushInterval = FLUSH_INTERVAL, enableSendBeacon = false } : LoggerOptions) : LoggerType {\n\n let events : Array<{| level : $Values, event : string, payload : Payload |}> = [];\n let tracking : Array = [];\n\n const payloadBuilders : Array = [];\n const metaBuilders : Array = [];\n const trackingBuilders : Array = [];\n const headerBuilders : Array = [];\n\n function print(level : $Values, event : string, payload : Payload) {\n\n if (!isBrowser() || !window.console || !window.console.log) {\n return;\n }\n\n if (LOG_LEVEL_PRIORITY.indexOf(level) > LOG_LEVEL_PRIORITY.indexOf(logLevel)) {\n return;\n }\n\n const args = [ event ];\n\n args.push(payload);\n\n if (payload.error || payload.warning) {\n args.push('\\n\\n', payload.error || payload.warning);\n }\n\n try {\n if (window.console[level] && window.console[level].apply) {\n window.console[level].apply(window.console, args);\n } else if (window.console.log && window.console.log.apply) {\n window.console.log.apply(window.console, args);\n }\n } catch (err) {\n // pass\n }\n }\n\n function immediateFlush() : ZalgoPromise {\n return ZalgoPromise.try(() => {\n if (!isBrowser() || window.location.protocol === PROTOCOL.FILE) {\n return;\n }\n\n if (!events.length && !tracking.length) {\n return;\n }\n\n const meta = {};\n for (const builder of metaBuilders) {\n extendIfDefined(meta, builder(meta));\n }\n\n const headers = {};\n for (const builder of headerBuilders) {\n extendIfDefined(headers, builder(headers));\n }\n\n const res = transport({\n method: 'POST',\n url,\n headers,\n json: {\n events,\n meta,\n tracking\n },\n enableSendBeacon\n });\n\n events = [];\n tracking = [];\n\n return res.then(noop);\n });\n }\n\n const flush = promiseDebounce(immediateFlush);\n\n function enqueue(level : $Values, event : string, payload : Payload) {\n\n events.push({\n level,\n event,\n payload\n });\n\n if (AUTO_FLUSH_LEVEL.indexOf(level) !== -1) {\n flush();\n }\n }\n\n function log(level : $Values, event : string, payload = {}) : LoggerType {\n\n if (!isBrowser()) {\n return logger; // eslint-disable-line no-use-before-define\n }\n\n if (prefix) {\n event = `${ prefix }_${ event }`;\n }\n\n const logPayload : Payload = {\n ...objFilter(payload),\n timestamp: Date.now().toString()\n };\n\n for (const builder of payloadBuilders) {\n extendIfDefined(logPayload, builder(logPayload));\n }\n\n enqueue(level, event, logPayload);\n print(level, event, logPayload);\n\n return logger; // eslint-disable-line no-use-before-define\n }\n\n function addBuilder(builders, builder) : LoggerType {\n builders.push(builder);\n return logger; // eslint-disable-line no-use-before-define\n }\n\n function addPayloadBuilder(builder) : LoggerType {\n return addBuilder(payloadBuilders, builder);\n }\n\n function addMetaBuilder(builder) : LoggerType {\n return addBuilder(metaBuilders, builder);\n }\n\n function addTrackingBuilder(builder) : LoggerType {\n return addBuilder(trackingBuilders, builder);\n }\n\n function addHeaderBuilder(builder) : LoggerType {\n return addBuilder(headerBuilders, builder);\n }\n\n function debug(event, payload) : LoggerType {\n return log(LOG_LEVEL.DEBUG, event, payload);\n }\n\n function info(event, payload) : LoggerType {\n return log(LOG_LEVEL.INFO, event, payload);\n }\n\n function warn(event, payload) : LoggerType {\n return log(LOG_LEVEL.WARN, event, payload);\n }\n\n function error(event, payload) : LoggerType {\n return log(LOG_LEVEL.ERROR, event, payload);\n }\n\n function track(payload = {}) : LoggerType {\n if (!isBrowser()) {\n return logger; // eslint-disable-line no-use-before-define\n }\n\n const trackingPayload : Payload = objFilter(payload);\n\n for (const builder of trackingBuilders) {\n extendIfDefined(trackingPayload, builder(trackingPayload));\n }\n\n print(LOG_LEVEL.DEBUG, 'track', trackingPayload);\n tracking.push(trackingPayload);\n\n return logger; // eslint-disable-line no-use-before-define\n }\n\n function setTransport(newTransport : Transport) : LoggerType {\n transport = newTransport;\n return logger; // eslint-disable-line no-use-before-define\n }\n\n if (isBrowser()) {\n safeInterval(flush, flushInterval);\n }\n\n if (typeof window === 'object') {\n window.addEventListener('beforeunload', () => {\n immediateFlush();\n });\n\n window.addEventListener('unload', () => {\n immediateFlush();\n });\n }\n\n const logger = {\n debug,\n info,\n warn,\n error,\n track,\n flush,\n immediateFlush,\n addPayloadBuilder,\n addMetaBuilder,\n addTrackingBuilder,\n addHeaderBuilder,\n setTransport\n };\n\n return logger;\n}\n"],"sourceRoot":""} \ No newline at end of file diff --git a/dist/module/logger.js b/dist/module/logger.js index 80f2280..1c7d356 100644 --- a/dist/module/logger.js +++ b/dist/module/logger.js @@ -48,9 +48,7 @@ export function Logger(_ref2) { _ref2$flushInterval = _ref2.flushInterval, flushInterval = _ref2$flushInterval === void 0 ? FLUSH_INTERVAL : _ref2$flushInterval, _ref2$enableSendBeaco = _ref2.enableSendBeacon, - enableSendBeacon = _ref2$enableSendBeaco === void 0 ? false : _ref2$enableSendBeaco, - _ref2$enableBrowserLo = _ref2.enableBrowserLogging, - enableBrowserLogging = _ref2$enableBrowserLo === void 0 ? true : _ref2$enableBrowserLo; + enableSendBeacon = _ref2$enableSendBeaco === void 0 ? false : _ref2$enableSendBeaco; var events = []; var tracking = []; var payloadBuilders = []; @@ -59,7 +57,7 @@ export function Logger(_ref2) { var headerBuilders = []; function print(level, event, payload) { - if (!isBrowser() || !window.console || !window.console.log || !enableBrowserLogging) { + if (!isBrowser() || !window.console || !window.console.log) { return; }