{"browsers":{"android":"<=4","chrome":"<=24","firefox":"<=37","firefox_mob":"*","ie":"6 - 9","ie_mob":"<=9","ios_chr":"*","ios_saf":"*","op_mob":"*","opera":"<=12","safari":"*"},"spec":"http://www.w3.org/TR/user-timing/","license":"MIT","repo":"https://github.com/nicjansma/usertiming.js","docs":"https://developer.mozilla.org/en-US/docs/Web/API/User_Timing_API","baseDir":"UserTiming","hasTests":true,"rawSource":"\n// UserTiming\n/* eslint-env browser,amd,node */\r\n//\r\n// usertiming.js\r\n//\r\n// A polyfill for UserTiming (http://www.w3.org/TR/user-timing/)\r\n//\r\n// Copyright 2013 Nic Jansma\r\n// http://nicj.net\r\n//\r\n// https://github.com/nicjansma/usertiming.js\r\n//\r\n// Licensed under the MIT license\r\n//\r\n(function(window) {\r\n    \"use strict\";\r\n\r\n    // allow running in Node.js environment\r\n    if (typeof window === \"undefined\") {\r\n        window = {};\r\n    }\r\n\r\n    // prepare base perf object\r\n    if (typeof window.performance === \"undefined\") {\r\n        window.performance = {};\r\n    }\r\n\r\n    // We need to keep a global reference to the window.performance object to\r\n    // prevent any added properties from being garbage-collected in Safari 8.\r\n    // https://bugs.webkit.org/show_bug.cgi?id=137407\r\n    window._perfRefForUserTimingPolyfill = window.performance;\r\n\r\n    //\r\n    // Note what we shimmed\r\n    //\r\n    window.performance.userTimingJsNow = false;\r\n    window.performance.userTimingJsNowPrefixed = false;\r\n    window.performance.userTimingJsUserTiming = false;\r\n    window.performance.userTimingJsUserTimingPrefixed = false;\r\n    window.performance.userTimingJsPerformanceTimeline = false;\r\n    window.performance.userTimingJsPerformanceTimelinePrefixed = false;\r\n\r\n    // for prefixed support\r\n    var prefixes = [];\r\n    var methods = [];\r\n    var methodTest = null;\r\n    var i, j;\r\n\r\n    //\r\n    // window.performance.now() shim\r\n    //  http://www.w3.org/TR/hr-time/\r\n    //\r\n    if (typeof window.performance.now !== \"function\") {\r\n        window.performance.userTimingJsNow = true;\r\n\r\n        // copy prefixed version over if it exists\r\n        methods = [\"webkitNow\", \"msNow\", \"mozNow\"];\r\n\r\n        for (i = 0; i < methods.length; i++) {\r\n            if (typeof window.performance[methods[i]] === \"function\") {\r\n                window.performance.now = window.performance[methods[i]];\r\n\r\n                window.performance.userTimingJsNowPrefixed = true;\r\n\r\n                break;\r\n            }\r\n        }\r\n\r\n        //\r\n        // now() should be a DOMHighResTimeStamp, which is defined as being a time relative\r\n        // to navigationStart of the PerformanceTiming (PT) interface.  If this browser supports\r\n        // PT, use that as our relative start.  Otherwise, use \"now\" as the start and all other\r\n        // now() calls will be relative to our initialization.\r\n        //\r\n\r\n        var nowOffset = +(new Date());\r\n        if (window.performance.timing && window.performance.timing.navigationStart) {\r\n            nowOffset = window.performance.timing.navigationStart;\r\n        }\r\n\r\n        if (typeof window.performance.now !== \"function\") {\r\n            // No browser support, fall back to Date.now\r\n            if (Date.now) {\r\n                window.performance.now = function() {\r\n                    return Date.now() - nowOffset;\r\n                };\r\n            } else {\r\n                // no Date.now support, get the time from new Date()\r\n                window.performance.now = function() {\r\n                    return +(new Date()) - nowOffset;\r\n                };\r\n            }\r\n        }\r\n    }\r\n\r\n    //\r\n    // PerformanceTimeline (PT) shims\r\n    //  http://www.w3.org/TR/performance-timeline/\r\n    //\r\n\r\n    /**\r\n     * Adds an object to our internal Performance Timeline array.\r\n     *\r\n     * Will be blank if the environment supports PT.\r\n     */\r\n    var addToPerformanceTimeline = function() {\r\n    };\r\n\r\n    /**\r\n     * Clears the specified entry types from our timeline array.\r\n     *\r\n     * Will be blank if the environment supports PT.\r\n     */\r\n    var clearEntriesFromPerformanceTimeline = function() {\r\n    };\r\n\r\n    // performance timeline array\r\n    var performanceTimeline = [];\r\n\r\n    // whether or not the timeline will require sort on getEntries()\r\n    var performanceTimelineRequiresSort = false;\r\n\r\n    // whether or not ResourceTiming is natively supported but UserTiming is\r\n    // not (eg Firefox 35)\r\n    var hasNativeGetEntriesButNotUserTiming = false;\r\n\r\n    //\r\n    // If getEntries() and mark() aren't defined, we'll assume\r\n    // we have to shim at least some PT functions.\r\n    //\r\n    if (typeof window.performance.getEntries !== \"function\" ||\r\n        typeof window.performance.mark !== \"function\") {\r\n\r\n        if (typeof window.performance.getEntries === \"function\" &&\r\n            typeof window.performance.mark !== \"function\") {\r\n            hasNativeGetEntriesButNotUserTiming = true;\r\n        }\r\n\r\n        window.performance.userTimingJsPerformanceTimeline = true;\r\n\r\n        // copy prefixed version over if it exists\r\n        prefixes = [\"webkit\", \"moz\"];\r\n        methods = [\"getEntries\", \"getEntriesByName\", \"getEntriesByType\"];\r\n\r\n        for (i = 0; i < methods.length; i++) {\r\n            for (j = 0; j < prefixes.length; j++) {\r\n                // prefixed method will likely have an upper-case first letter\r\n                methodTest = prefixes[j] + methods[i].substr(0, 1).toUpperCase() + methods[i].substr(1);\r\n\r\n                if (typeof window.performance[methodTest] === \"function\") {\r\n                    window.performance[methods[i]] = window.performance[methodTest];\r\n\r\n                    window.performance.userTimingJsPerformanceTimelinePrefixed = true;\r\n                }\r\n            }\r\n        }\r\n\r\n        /**\r\n         * Adds an object to our internal Performance Timeline array.\r\n         *\r\n         * @param {Object} obj PerformanceEntry\r\n         */\r\n        addToPerformanceTimeline = function(obj) {\r\n            performanceTimeline.push(obj);\r\n\r\n            //\r\n            // If we insert a measure, its startTime may be out of order\r\n            // from the rest of the entries because the use can use any\r\n            // mark as the start time.  If so, note we have to sort it before\r\n            // returning getEntries();\r\n            //\r\n            if (obj.entryType === \"measure\") {\r\n                performanceTimelineRequiresSort = true;\r\n            }\r\n        };\r\n\r\n        /**\r\n         * Ensures our PT array is in the correct sorted order (by startTime)\r\n         */\r\n        var ensurePerformanceTimelineOrder = function() {\r\n            if (!performanceTimelineRequiresSort) {\r\n                return;\r\n            }\r\n\r\n            //\r\n            // Measures, which may be in this list, may enter the list in\r\n            // an unsorted order. For example:\r\n            //\r\n            //  1. measure(\"a\")\r\n            //  2. mark(\"start_mark\")\r\n            //  3. measure(\"b\", \"start_mark\")\r\n            //  4. measure(\"c\")\r\n            //  5. getEntries()\r\n            //\r\n            // When calling #5, we should return [a,c,b] because technically the start time\r\n            // of c is \"0\" (navigationStart), which will occur before b's start time due to the mark.\r\n            //\r\n            performanceTimeline.sort(function(a, b) {\r\n                return a.startTime - b.startTime;\r\n            });\r\n\r\n            performanceTimelineRequiresSort = false;\r\n        };\r\n\r\n        /**\r\n         * Clears the specified entry types from our timeline array.\r\n         *\r\n         * @param {string} entryType Entry type (eg \"mark\" or \"measure\")\r\n         * @param {string} [name] Entry name (optional)\r\n         */\r\n        clearEntriesFromPerformanceTimeline = function(entryType, name) {\r\n            // clear all entries from the perf timeline\r\n            i = 0;\r\n            while (i < performanceTimeline.length) {\r\n                if (performanceTimeline[i].entryType !== entryType) {\r\n                    // unmatched entry type\r\n                    i++;\r\n                    continue;\r\n                }\r\n\r\n                if (typeof name !== \"undefined\" && performanceTimeline[i].name !== name) {\r\n                    // unmatched name\r\n                    i++;\r\n                    continue;\r\n                }\r\n\r\n                // this entry matches our criteria, remove just it\r\n                performanceTimeline.splice(i, 1);\r\n            }\r\n        };\r\n\r\n        if (typeof window.performance.getEntries !== \"function\" || hasNativeGetEntriesButNotUserTiming) {\r\n            var origGetEntries = window.performance.getEntries;\r\n\r\n            /**\r\n             * Gets all entries from the Performance Timeline.\r\n             * http://www.w3.org/TR/performance-timeline/#dom-performance-getentries\r\n             *\r\n             * NOTE: This will only ever return marks and measures.\r\n             *\r\n             * @returns {PerformanceEntry[]} Array of PerformanceEntrys\r\n             */\r\n            window.performance.getEntries = function() {\r\n                ensurePerformanceTimelineOrder();\r\n\r\n                // get a copy of all of our entries\r\n                var entries = performanceTimeline.slice(0);\r\n\r\n                // if there was a native version of getEntries, add that\r\n                if (hasNativeGetEntriesButNotUserTiming && origGetEntries) {\r\n                    // merge in native\r\n                    Array.prototype.push.apply(entries, origGetEntries.call(window.performance));\r\n\r\n                    // sort by startTime\r\n                    entries.sort(function(a, b) {\r\n                        return a.startTime - b.startTime;\r\n                    });\r\n                }\r\n\r\n                return entries;\r\n            };\r\n        }\r\n\r\n        if (typeof window.performance.getEntriesByType !== \"function\" || hasNativeGetEntriesButNotUserTiming) {\r\n            var origGetEntriesByType = window.performance.getEntriesByType;\r\n\r\n            /**\r\n             * Gets all entries from the Performance Timeline of the specified type.\r\n             * http://www.w3.org/TR/performance-timeline/#dom-performance-getentriesbytype\r\n             *\r\n             * NOTE: This will only work for marks and measures.\r\n             *\r\n             * @param {string} entryType Entry type (eg \"mark\" or \"measure\")\r\n             *\r\n             * @returns {PerformanceEntry[]} Array of PerformanceEntrys\r\n             */\r\n            window.performance.getEntriesByType = function(entryType) {\r\n                // we only support marks/measures\r\n                if (typeof entryType === \"undefined\" ||\r\n                    (entryType !== \"mark\" && entryType !== \"measure\")) {\r\n\r\n                    if (hasNativeGetEntriesButNotUserTiming && origGetEntriesByType) {\r\n                        // native version exists, forward\r\n                        return origGetEntriesByType.call(window.performance, entryType);\r\n                    }\r\n\r\n                    return [];\r\n                }\r\n\r\n                // see note in ensurePerformanceTimelineOrder() on why this is required\r\n                if (entryType === \"measure\") {\r\n                    ensurePerformanceTimelineOrder();\r\n                }\r\n\r\n                // find all entries of entryType\r\n                var entries = [];\r\n                for (i = 0; i < performanceTimeline.length; i++) {\r\n                    if (performanceTimeline[i].entryType === entryType) {\r\n                        entries.push(performanceTimeline[i]);\r\n                    }\r\n                }\r\n\r\n                return entries;\r\n            };\r\n        }\r\n\r\n        if (typeof window.performance.getEntriesByName !== \"function\" || hasNativeGetEntriesButNotUserTiming) {\r\n            var origGetEntriesByName = window.performance.getEntriesByName;\r\n\r\n            /**\r\n             * Gets all entries from the Performance Timeline of the specified\r\n             * name, and optionally, type.\r\n             * http://www.w3.org/TR/performance-timeline/#dom-performance-getentriesbyname\r\n             *\r\n             * NOTE: This will only work for marks and measures.\r\n             *\r\n             * @param {string} name Entry name\r\n             * @param {string} [entryType] Entry type (eg \"mark\" or \"measure\")\r\n             *\r\n             * @returns {PerformanceEntry[]} Array of PerformanceEntrys\r\n             */\r\n            window.performance.getEntriesByName = function(name, entryType) {\r\n                if (entryType && entryType !== \"mark\" && entryType !== \"measure\") {\r\n                    if (hasNativeGetEntriesButNotUserTiming && origGetEntriesByName) {\r\n                        // native version exists, forward\r\n                        return origGetEntriesByName.call(window.performance, name, entryType);\r\n                    }\r\n\r\n                    return [];\r\n                }\r\n\r\n                // see note in ensurePerformanceTimelineOrder() on why this is required\r\n                if (typeof entryType !== \"undefined\" && entryType === \"measure\") {\r\n                    ensurePerformanceTimelineOrder();\r\n                }\r\n\r\n                // find all entries of the name and (optionally) type\r\n                var entries = [];\r\n                for (i = 0; i < performanceTimeline.length; i++) {\r\n                    if (typeof entryType !== \"undefined\" &&\r\n                        performanceTimeline[i].entryType !== entryType) {\r\n                        continue;\r\n                    }\r\n\r\n                    if (performanceTimeline[i].name === name) {\r\n                        entries.push(performanceTimeline[i]);\r\n                    }\r\n                }\r\n\r\n                if (hasNativeGetEntriesButNotUserTiming && origGetEntriesByName) {\r\n                    // merge in native\r\n                    Array.prototype.push.apply(entries, origGetEntriesByName.call(window.performance, name, entryType));\r\n\r\n                    // sort by startTime\r\n                    entries.sort(function(a, b) {\r\n                        return a.startTime - b.startTime;\r\n                    });\r\n                }\r\n\r\n                return entries;\r\n            };\r\n        }\r\n    }\r\n\r\n    //\r\n    // UserTiming support\r\n    //\r\n    if (typeof window.performance.mark !== \"function\") {\r\n        window.performance.userTimingJsUserTiming = true;\r\n\r\n        // copy prefixed version over if it exists\r\n        prefixes = [\"webkit\", \"moz\", \"ms\"];\r\n        methods = [\"mark\", \"measure\", \"clearMarks\", \"clearMeasures\"];\r\n\r\n        for (i = 0; i < methods.length; i++) {\r\n            for (j = 0; j < prefixes.length; j++) {\r\n                // prefixed method will likely have an upper-case first letter\r\n                methodTest = prefixes[j] + methods[i].substr(0, 1).toUpperCase() + methods[i].substr(1);\r\n\r\n                if (typeof window.performance[methodTest] === \"function\") {\r\n                    window.performance[methods[i]] = window.performance[methodTest];\r\n\r\n                    window.performance.userTimingJsUserTimingPrefixed = true;\r\n                }\r\n            }\r\n        }\r\n\r\n        // only used for measure(), to quickly see the latest timestamp of a mark\r\n        var marks = {};\r\n\r\n        if (typeof window.performance.mark !== \"function\") {\r\n            /**\r\n             * UserTiming mark\r\n             * http://www.w3.org/TR/user-timing/#dom-performance-mark\r\n             *\r\n             * @param {string} markName Mark name\r\n             */\r\n            window.performance.mark = function(markName) {\r\n                var now = window.performance.now();\r\n\r\n                // mark name is required\r\n                if (typeof markName === \"undefined\") {\r\n                    throw new SyntaxError(\"Mark name must be specified\");\r\n                }\r\n\r\n                // mark name can't be a NT timestamp\r\n                if (window.performance.timing && markName in window.performance.timing) {\r\n                    throw new SyntaxError(\"Mark name is not allowed\");\r\n                }\r\n\r\n                if (!marks[markName]) {\r\n                    marks[markName] = [];\r\n                }\r\n\r\n                marks[markName].push(now);\r\n\r\n                // add to perf timeline as well\r\n                addToPerformanceTimeline({\r\n                    entryType: \"mark\",\r\n                    name: markName,\r\n                    startTime: now,\r\n                    duration: 0\r\n                });\r\n            };\r\n        }\r\n\r\n        if (typeof window.performance.clearMarks !== \"function\") {\r\n            /**\r\n             * UserTiming clear marks\r\n             * http://www.w3.org/TR/user-timing/#dom-performance-clearmarks\r\n             *\r\n             * @param {string} markName Mark name\r\n             */\r\n            window.performance.clearMarks = function(markName) {\r\n                if (!markName) {\r\n                    // clear all marks\r\n                    marks = {};\r\n                } else {\r\n                    marks[markName] = [];\r\n                }\r\n\r\n                clearEntriesFromPerformanceTimeline(\"mark\", markName);\r\n            };\r\n        }\r\n\r\n        if (typeof window.performance.measure !== \"function\") {\r\n            /**\r\n             * UserTiming measure\r\n             * http://www.w3.org/TR/user-timing/#dom-performance-measure\r\n             *\r\n             * @param {string} measureName Measure name\r\n             * @param {string} [startMark] Start mark name\r\n             * @param {string} [endMark] End mark name\r\n             */\r\n            window.performance.measure = function(measureName, startMark, endMark) {\r\n                var now = window.performance.now();\r\n\r\n                if (typeof measureName === \"undefined\") {\r\n                    throw new SyntaxError(\"Measure must be specified\");\r\n                }\r\n\r\n                // if there isn't a startMark, we measure from navigationStart to now\r\n                if (!startMark) {\r\n                    // add to perf timeline as well\r\n                    addToPerformanceTimeline({\r\n                        entryType: \"measure\",\r\n                        name: measureName,\r\n                        startTime: 0,\r\n                        duration: now\r\n                    });\r\n\r\n                    return;\r\n                }\r\n\r\n                //\r\n                // If there is a startMark, check for it first in the NavigationTiming interface,\r\n                // then check our own marks.\r\n                //\r\n                var startMarkTime = 0;\r\n                if (window.performance.timing && startMark in window.performance.timing) {\r\n                    // mark cannot have a timing of 0\r\n                    if (startMark !== \"navigationStart\" && window.performance.timing[startMark] === 0) {\r\n                        throw new Error(startMark + \" has a timing of 0\");\r\n                    }\r\n\r\n                    // time is the offset of this mark to navigationStart's time\r\n                    startMarkTime = window.performance.timing[startMark] - window.performance.timing.navigationStart;\r\n                } else if (startMark in marks) {\r\n                    startMarkTime = marks[startMark][marks[startMark].length - 1];\r\n                } else {\r\n                    throw new Error(startMark + \" mark not found\");\r\n                }\r\n\r\n                //\r\n                // If there is a endMark, check for it first in the NavigationTiming interface,\r\n                // then check our own marks.\r\n                //\r\n                var endMarkTime = now;\r\n\r\n                if (endMark) {\r\n                    endMarkTime = 0;\r\n\r\n                    if (window.performance.timing && endMark in window.performance.timing) {\r\n                        // mark cannot have a timing of 0\r\n                        if (endMark !== \"navigationStart\" && window.performance.timing[endMark] === 0) {\r\n                            throw new Error(endMark + \" has a timing of 0\");\r\n                        }\r\n\r\n                        // time is the offset of this mark to navigationStart's time\r\n                        endMarkTime = window.performance.timing[endMark] - window.performance.timing.navigationStart;\r\n                    } else if (endMark in marks) {\r\n                        endMarkTime = marks[endMark][marks[endMark].length - 1];\r\n                    } else {\r\n                        throw new Error(endMark + \" mark not found\");\r\n                    }\r\n                }\r\n\r\n                // add to our measure array\r\n                var duration = endMarkTime - startMarkTime;\r\n\r\n                // add to perf timeline as well\r\n                addToPerformanceTimeline({\r\n                    entryType: \"measure\",\r\n                    name: measureName,\r\n                    startTime: startMarkTime,\r\n                    duration: duration\r\n                });\r\n            };\r\n        }\r\n\r\n        if (typeof window.performance.clearMeasures !== \"function\") {\r\n            /**\r\n             * UserTiming clear measures\r\n             * http://www.w3.org/TR/user-timing/#dom-performance-clearmeasures\r\n             *\r\n             * @param {string} measureName Measure name\r\n             */\r\n            window.performance.clearMeasures = function(measureName) {\r\n                clearEntriesFromPerformanceTimeline(\"measure\", measureName);\r\n            };\r\n        }\r\n    }\r\n\r\n    //\r\n    // Export UserTiming to the appropriate location.\r\n    //\r\n    // When included directly via a script tag in the browser, we're good as we've been\r\n    // updating the window.performance object.\r\n    //\r\n    if (typeof define === \"function\" && define.amd) {\r\n        //\r\n        // AMD / RequireJS\r\n        //\r\n        define([], function() {\r\n            return window.performance;\r\n        });\r\n    } else if (typeof module !== \"undefined\" && typeof module.exports !== \"undefined\") {\r\n        //\r\n        // Node.js\r\n        //\r\n        module.exports = window.performance;\r\n    }\r\n}(typeof window !== \"undefined\" ? window : undefined));\r\n","minSource":"!function(e){\"use strict\";\"undefined\"==typeof e&&(e={}),\"undefined\"==typeof e.performance&&(e.performance={}),e._perfRefForUserTimingPolyfill=e.performance,e.performance.userTimingJsNow=!1,e.performance.userTimingJsNowPrefixed=!1,e.performance.userTimingJsUserTiming=!1,e.performance.userTimingJsUserTimingPrefixed=!1,e.performance.userTimingJsPerformanceTimeline=!1,e.performance.userTimingJsPerformanceTimelinePrefixed=!1;var r,n,o=[],t=[],i=null;if(\"function\"!=typeof e.performance.now){for(e.performance.userTimingJsNow=!0,t=[\"webkitNow\",\"msNow\",\"mozNow\"],r=0;r<t.length;r++)if(\"function\"==typeof e.performance[t[r]]){e.performance.now=e.performance[t[r]],e.performance.userTimingJsNowPrefixed=!0;break}var f=+new Date;e.performance.timing&&e.performance.timing.navigationStart&&(f=e.performance.timing.navigationStart),\"function\"!=typeof e.performance.now&&(Date.now?e.performance.now=function(){return Date.now()-f}:e.performance.now=function(){return+new Date-f})}var a=function(){},m=function(){},p=[],c=!1,s=!1;if(\"function\"!=typeof e.performance.getEntries||\"function\"!=typeof e.performance.mark){for(\"function\"==typeof e.performance.getEntries&&\"function\"!=typeof e.performance.mark&&(s=!0),e.performance.userTimingJsPerformanceTimeline=!0,o=[\"webkit\",\"moz\"],t=[\"getEntries\",\"getEntriesByName\",\"getEntriesByType\"],r=0;r<t.length;r++)for(n=0;n<o.length;n++)i=o[n]+t[r].substr(0,1).toUpperCase()+t[r].substr(1),\"function\"==typeof e.performance[i]&&(e.performance[t[r]]=e.performance[i],e.performance.userTimingJsPerformanceTimelinePrefixed=!0);a=function(e){p.push(e),\"measure\"===e.entryType&&(c=!0)};var u=function(){c&&(p.sort(function(e,r){return e.startTime-r.startTime}),c=!1)};if(m=function(e,n){for(r=0;r<p.length;)p[r].entryType===e&&(\"undefined\"==typeof n||p[r].name===n)?p.splice(r,1):r++},\"function\"!=typeof e.performance.getEntries||s){var y=e.performance.getEntries;e.performance.getEntries=function(){u();var r=p.slice(0);return s&&y&&(Array.prototype.push.apply(r,y.call(e.performance)),r.sort(function(e,r){return e.startTime-r.startTime})),r}}if(\"function\"!=typeof e.performance.getEntriesByType||s){var g=e.performance.getEntriesByType;e.performance.getEntriesByType=function(n){if(\"undefined\"==typeof n||\"mark\"!==n&&\"measure\"!==n)return s&&g?g.call(e.performance,n):[];\"measure\"===n&&u();var o=[];for(r=0;r<p.length;r++)p[r].entryType===n&&o.push(p[r]);return o}}if(\"function\"!=typeof e.performance.getEntriesByName||s){var d=e.performance.getEntriesByName;e.performance.getEntriesByName=function(n,o){if(o&&\"mark\"!==o&&\"measure\"!==o)return s&&d?d.call(e.performance,n,o):[];\"undefined\"!=typeof o&&\"measure\"===o&&u();var t=[];for(r=0;r<p.length;r++)\"undefined\"!=typeof o&&p[r].entryType!==o||p[r].name===n&&t.push(p[r]);return s&&d&&(Array.prototype.push.apply(t,d.call(e.performance,n,o)),t.sort(function(e,r){return e.startTime-r.startTime})),t}}}if(\"function\"!=typeof e.performance.mark){for(e.performance.userTimingJsUserTiming=!0,o=[\"webkit\",\"moz\",\"ms\"],t=[\"mark\",\"measure\",\"clearMarks\",\"clearMeasures\"],r=0;r<t.length;r++)for(n=0;n<o.length;n++)i=o[n]+t[r].substr(0,1).toUpperCase()+t[r].substr(1),\"function\"==typeof e.performance[i]&&(e.performance[t[r]]=e.performance[i],e.performance.userTimingJsUserTimingPrefixed=!0);var l={};\"function\"!=typeof e.performance.mark&&(e.performance.mark=function(r){var n=e.performance.now();if(\"undefined\"==typeof r)throw new SyntaxError(\"Mark name must be specified\");if(e.performance.timing&&r in e.performance.timing)throw new SyntaxError(\"Mark name is not allowed\");l[r]||(l[r]=[]),l[r].push(n),a({entryType:\"mark\",name:r,startTime:n,duration:0})}),\"function\"!=typeof e.performance.clearMarks&&(e.performance.clearMarks=function(e){e?l[e]=[]:l={},m(\"mark\",e)}),\"function\"!=typeof e.performance.measure&&(e.performance.measure=function(r,n,o){var t=e.performance.now();if(\"undefined\"==typeof r)throw new SyntaxError(\"Measure must be specified\");if(!n)return void a({entryType:\"measure\",name:r,startTime:0,duration:t});var i=0;if(e.performance.timing&&n in e.performance.timing){if(\"navigationStart\"!==n&&0===e.performance.timing[n])throw new Error(n+\" has a timing of 0\");i=e.performance.timing[n]-e.performance.timing.navigationStart}else{if(!(n in l))throw new Error(n+\" mark not found\");i=l[n][l[n].length-1]}var f=t;if(o)if(f=0,e.performance.timing&&o in e.performance.timing){if(\"navigationStart\"!==o&&0===e.performance.timing[o])throw new Error(o+\" has a timing of 0\");f=e.performance.timing[o]-e.performance.timing.navigationStart}else{if(!(o in l))throw new Error(o+\" mark not found\");f=l[o][l[o].length-1]}var m=f-i;a({entryType:\"measure\",name:r,startTime:i,duration:m})}),\"function\"!=typeof e.performance.clearMeasures&&(e.performance.clearMeasures=function(e){m(\"measure\",e)})}\"function\"==typeof define&&define.amd?define([],function(){return e.performance}):\"undefined\"!=typeof module&&\"undefined\"!=typeof module.exports&&(module.exports=e.performance)}(\"undefined\"!=typeof window?window:void 0);","detectSource":"'performance' in this && typeof this.performance.getEntriesByType === 'function' && typeof this.performance.mark === 'function'"}