@skylineos/clsp-player
Version:
Skyline Technology Solutions' CLSP Video Player. Stream video in near-real-time in modern browsers.
18 lines (16 loc) • 6.18 MB
JavaScript
/*
* ATTENTION: An "eval-source-map" devtool has been used.
* This devtool is neither made for production nor for readable output files.
* It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
* or disable the default devtool with "devtool: false".
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
*/
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ "./dist/clsp-player.min.js":
/*!*********************************!*\
!*** ./dist/clsp-player.min.js ***!
\*********************************/
/***/ ((module) => {
eval("(function webpackUniversalModuleDefinition(root, factory) {\n\tif(true)\n\t\tmodule.exports = factory();\n\telse {}\n})(self, () => {\nreturn /******/ (() => { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 909:\n/***/ ((module) => {\n\n\"use strict\";\n\n\n/* eslint no-console: off */\n\n/**\n * This file needs to use `require` rather than `import` to be able to be used\n * by webpack.\n *\n * We use this in the router as well, so keep it light and ES5 only!\n */\nmodule.exports = function (version, logLevel, disableLogging) {\n function Logger(prefix, prefixStyle) {\n if (logLevel === undefined && typeof window !== 'undefined') {\n var storedVersion = window.localStorage.getItem('skylineos.clsp-player.version');\n\n // Always reset the log level when the version changes\n if (storedVersion !== version) {\n window.localStorage.setItem('skylineos.clsp-player.logLevel', 0);\n window.localStorage.setItem('skylineos.clsp-player.version', version);\n }\n var storedLogLevel = Number(window.localStorage.getItem('skylineos.clsp-player.logLevel'));\n\n // The logLevel may be set in localstorage\n // e.g. localStorage.setItem('skylineos.clsp-player.logLevel', 3), then refresh\n logLevel = isNaN(storedLogLevel) || storedLogLevel < 0 ? 0 : storedLogLevel;\n window.localStorage.setItem('skylineos.clsp-player.logLevel', logLevel);\n }\n this.logLevel = logLevel;\n this.prefix = prefix;\n this.prefixStyle = prefixStyle;\n }\n Logger.logLevels = ['critical', 'error', 'warn', 'info', 'debug', 'silly'];\n Logger.factory = function (prefix, prefixStyle) {\n return new Logger(prefix || '', prefixStyle);\n };\n Logger.prototype._constructMessage = function (type, message) {\n var logMessage = '(' + type + ')' + ' --> ' + message;\n\n // @see - https://developers.google.com/web/tools/chrome-devtools/console/console-write#string_substitution_and_formatting\n if (this.prefix && this.prefixStyle && this.logLevel > 1) {\n return ['%c' + this.prefix, this.prefixStyle, logMessage];\n }\n if (this.prefix) {\n return [this.prefix, logMessage];\n }\n return [logMessage];\n };\n var sillyIndex = 5;\n var debugIndex = 4;\n var infoIndex = 3;\n var warnIndex = 2;\n var errorIndex = 1;\n var criticalIndex = 0;\n Logger.prototype.silly = function (message) {\n if (this.logLevel < sillyIndex || disableLogging) {\n return;\n }\n console.log.apply(console, this._constructMessage(Logger.logLevels[sillyIndex], message));\n };\n Logger.prototype.debug = function (message) {\n if (this.logLevel < debugIndex || disableLogging) {\n return;\n }\n console.log.apply(console, this._constructMessage(Logger.logLevels[debugIndex], message));\n };\n Logger.prototype.info = function (message) {\n if (this.logLevel < infoIndex || disableLogging) {\n return;\n }\n console.log.apply(console, this._constructMessage(Logger.logLevels[infoIndex], message));\n };\n Logger.prototype.warn = function (message) {\n if (this.logLevel < warnIndex || disableLogging) {\n return;\n }\n console.warn.apply(console, this._constructMessage(Logger.logLevels[warnIndex], message));\n };\n Logger.prototype.error = function (message) {\n if (this.logLevel < errorIndex || disableLogging) {\n return;\n }\n console.error.apply(console, this._constructMessage(Logger.logLevels[errorIndex], message));\n };\n Logger.prototype.critical = function (message) {\n if (disableLogging) {\n return;\n }\n console.error.apply(console, this._constructMessage(Logger.logLevels[criticalIndex], message));\n };\n return Logger;\n};\n\n/***/ }),\n\n/***/ 8192:\n/***/ ((module, __unused_webpack_exports, __nested_webpack_require_3917__) => {\n\n\"use strict\";\n\n\n/**\n * This file needs to use `require` rather than `import` to be able to be used\n * by webpack.\n */\nvar _indexOfInstanceProperty = __nested_webpack_require_3917__(4007);\nvar _parseInt = __nested_webpack_require_3917__(6586);\nvar packageJson = __nested_webpack_require_3917__(8330);\nvar Logger = __nested_webpack_require_3917__(909);\nvar _isPlayerLoggingEnabled = true;\n\n// CLSP default port for SFS >= 5.2.0 is 80\n// CLSP default port for SFS < 5.2.0 is 9001\nvar DEFAULT_CLSP_PORT = 80;\nvar DEFAULT_CLSPS_PORT = 443;\n\n// Locally-scoped value that maintains the clsp and clsps port states.\n//\n// @see - getDefaultStreamPort\n// @see - setDefaultStreamPort\n//\n// @todo - state / config could be managed better than this\nvar streamPorts = {\n clsp: DEFAULT_CLSP_PORT,\n clsps: DEFAULT_CLSPS_PORT\n};\n\n/**\n * The name of the CLSP Player library as defined in `package.json` without the\n * group name.\n *\n * @type {String}\n */\nvar name = packageJson.name.split('/').pop();\n\n/**\n * The version of the CLSP Player library. Follows semver.\n *\n * @type {String}\n */\nvar version = packageJson.version;\n\n// @todo - remove this side-effect\nvar logger = Logger(version).factory();\n\n/**\n * The oldest Chrome browser version supported by CLSP Player.\n *\n * @type {Number}\n */\nvar MINIMUM_CHROME_VERSION = 53;\n\n/**\n * The MIME type required for CLSP Player to be able to play the stream.\n *\n * @todo - this mime type, though used in the videojs plugin, and\n * seemingly enforced, is not actually enforced. The only enforcement\n * done is requiring the user provide this string on the video element\n * in the DOM. The codecs that are supplied by the SFS's vary. Here\n * are some \"valid\", though not enforced mimeCodec values I have come\n * across:\n * - video/mp4; codecs=\"avc1.4DE016\"\n * - video/mp4; codecs=\"avc1.42E00C\"\n * - video/mp4; codecs=\"avc1.42E00D\"\n *\n * @type {String}\n */\nvar SUPPORTED_MIME_TYPE = \"video/mp4; codecs='avc1.42E01E'\";\n\n/**\n * The amount of time (in seconds) before a stream times out.\n *\n * Note that this timeout value should be treated as the minimum value to\n * support Vero tours and high-quality streams.\n *\n * @type {Number}\n */\nvar DEFAULT_STREAM_TIMEOUT = 20;\n\n/**\n * Determine whether or not the CLSP Player is supported in the current browser.\n *\n * @todo - we are currently manually checking useragentstring - we should find a\n * library that can check browser type for us\n *\n * @returns {Boolean}\n * `true` if the browser is supported by CLSP Player\n * `false` if the browser is not supported by CLSP Player\n */\nfunction isBrowserCompatable() {\n var _context, _context2, _context3;\n // @todo - at one time, this was needed for browsers on MacOS - is this still\n // necessary?\n window.MediaSource = window.MediaSource || window.WebKitMediaSource;\n if (!window.MediaSource) {\n console.error('Media Source Extensions not supported in your browser, unable to load CLSP Player');\n return false;\n }\n var isInternetExplorer = _indexOfInstanceProperty(_context = navigator.userAgent.toLowerCase()).call(_context, 'trident') > -1;\n if (isInternetExplorer) {\n logger.debug('Detected Internet Explorer browser, which is not supported.');\n return false;\n }\n var isEdge = _indexOfInstanceProperty(_context2 = navigator.userAgent.toLowerCase()).call(_context2, 'edge') > -1;\n if (isEdge) {\n logger.debug('Detected older Edge browser, which is not supported');\n return false;\n }\n var isFirefox = _indexOfInstanceProperty(_context3 = navigator.userAgent.toLowerCase()).call(_context3, 'firefox') > -1;\n if (isFirefox) {\n logger.debug('Detected Firefox browser');\n return true;\n }\n\n // Most browsers have \"Chrome\" in their user agent. The above filters rule\n // out Internet Explorer and Edge, so we are going to assume that if we're at\n // this point, we're really dealing with Chrome.\n var isChrome = Boolean(window.chrome);\n if (!isChrome) {\n return false;\n }\n try {\n // Rather than accounting for match returning null, we'll catch the error\n var chromeVersion = _parseInt(navigator.userAgent.match(/Chrom(e|ium)\\/([0-9]+)\\./)[2], 10);\n logger.debug(\"Detected Chrome version \".concat(chromeVersion));\n return chromeVersion >= MINIMUM_CHROME_VERSION;\n } catch (error) {\n logger.critical('Unable to detect Chrome version');\n logger.critical(error);\n return false;\n }\n}\n\n/**\n * Check to see if the passed mimeType is supported by CLSP Player.\n *\n * @param {String} mimeType\n * Will check to see if this mimeType is supported\n *\n * @returns {Boolean}\n * `true` if the mimeType is supported by CLSP Player\n * `false` if the mimeType is not supported by CLSP Player\n */\nfunction isSupportedMimeType(mimeType) {\n return mimeType === SUPPORTED_MIME_TYPE;\n}\n\n/**\n * @typedef {Object} PageVisibilityApiPropertyNames\n * @property {String} hiddenStateName\n * The property name used for the `document.hidden` property\n * @property {String} visibilityChangeEventName\n * The property name used for the `document.visibilityChange` event name\n */\n\n/**\n * Get the property names used by this browser for the Page Visibility API.\n *\n * @returns {PageVisibilityApiPropertyNames}\n */\nfunction getWindowStateNames() {\n logger.debug('Determining Page_Visibility_API property names.');\n\n // @todo - this check is needed to support these utils being imported by\n // webpack. there is probably a more elegant way to handle this scenario.\n if (typeof document === 'undefined') {\n return {\n hiddenStateName: '',\n visibilityChangeEventName: ''\n };\n }\n\n // @see - https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API\n if (typeof document.hidden !== 'undefined') {\n logger.debug('Using standard Page_Visibility_API property names.');\n return {\n hiddenStateName: 'hidden',\n visibilityChangeEventName: 'visibilitychange'\n };\n }\n\n // @todo - do we need this since we don't support IE or old Edge?\n if (typeof document.msHidden !== 'undefined') {\n logger.debug('Using Microsoft Page_Visibility_API property names.');\n return {\n hiddenStateName: 'msHidden',\n visibilityChangeEventName: 'msvisibilitychange'\n };\n }\n if (typeof document.webkitHidden !== 'undefined') {\n logger.debug('Using Webkit Page_Visibility_API property names.');\n return {\n hiddenStateName: 'webkitHidden',\n visibilityChangeEventName: 'webkitvisibilitychange'\n };\n }\n logger.critical('Unable to use the page visibility api - switching tabs and minimizing the page may result in slow downs and page crashes.');\n return {\n hiddenStateName: '',\n visibilityChangeEventName: ''\n };\n}\n\n/**\n * Get the default port number for the given protocol.\n *\n * @param {String} protocol\n * The protocol to get the default port for. Must be a known protocol (e.g.\n * `clsp` or `clsps`)\n */\nfunction getDefaultStreamPort(protocol) {\n return streamPorts[protocol];\n}\n\n/**\n * Set the default port number for the given protocol.\n *\n * @param {String} protocol\n * The protocol to set the default port for. Must be a known protocol (e.g.\n * `clsp` or `clsps`)\n */\nfunction setDefaultStreamPort(protocol, port) {\n streamPorts[protocol] = port;\n}\nfunction enablePlayerLogging() {\n _isPlayerLoggingEnabled = true;\n}\nfunction disablePlayerLogging() {\n _isPlayerLoggingEnabled = false;\n}\nfunction isPlayerLoggingDisabled() {\n return !_isPlayerLoggingEnabled;\n}\nvar windowStateNames = getWindowStateNames();\nfunction isDocumentHidden() {\n return document[windowStateNames.hiddenStateName];\n}\nfunction isOnline() {\n return window.navigator.onLine;\n}\nmodule.exports = {\n name: name,\n version: version,\n MINIMUM_CHROME_VERSION: MINIMUM_CHROME_VERSION,\n SUPPORTED_MIME_TYPE: SUPPORTED_MIME_TYPE,\n DEFAULT_STREAM_TIMEOUT: DEFAULT_STREAM_TIMEOUT,\n supported: isBrowserCompatable,\n isSupportedMimeType: isSupportedMimeType,\n windowStateNames: windowStateNames,\n isDocumentHidden: isDocumentHidden,\n isOnline: isOnline,\n getDefaultStreamPort: getDefaultStreamPort,\n setDefaultStreamPort: setDefaultStreamPort,\n enablePlayerLogging: enablePlayerLogging,\n disablePlayerLogging: disablePlayerLogging,\n isPlayerLoggingDisabled: isPlayerLoggingDisabled\n};\n\n/***/ }),\n\n/***/ 228:\n/***/ ((module) => {\n\n\"use strict\";\n\n\nvar has = Object.prototype.hasOwnProperty\n , prefix = '~';\n\n/**\n * Constructor to create a storage for our `EE` objects.\n * An `Events` instance is a plain object whose properties are event names.\n *\n * @constructor\n * @private\n */\nfunction Events() {}\n\n//\n// We try to not inherit from `Object.prototype`. In some engines creating an\n// instance in this way is faster than calling `Object.create(null)` directly.\n// If `Object.create(null)` is not supported we prefix the event names with a\n// character to make sure that the built-in object properties are not\n// overridden or used as an attack vector.\n//\nif (Object.create) {\n Events.prototype = Object.create(null);\n\n //\n // This hack is needed because the `__proto__` property is still inherited in\n // some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.\n //\n if (!new Events().__proto__) prefix = false;\n}\n\n/**\n * Representation of a single event listener.\n *\n * @param {Function} fn The listener function.\n * @param {*} context The context to invoke the listener with.\n * @param {Boolean} [once=false] Specify if the listener is a one-time listener.\n * @constructor\n * @private\n */\nfunction EE(fn, context, once) {\n this.fn = fn;\n this.context = context;\n this.once = once || false;\n}\n\n/**\n * Add a listener for a given event.\n *\n * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} context The context to invoke the listener with.\n * @param {Boolean} once Specify if the listener is a one-time listener.\n * @returns {EventEmitter}\n * @private\n */\nfunction addListener(emitter, event, fn, context, once) {\n if (typeof fn !== 'function') {\n throw new TypeError('The listener must be a function');\n }\n\n var listener = new EE(fn, context || emitter, once)\n , evt = prefix ? prefix + event : event;\n\n if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;\n else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);\n else emitter._events[evt] = [emitter._events[evt], listener];\n\n return emitter;\n}\n\n/**\n * Clear event by name.\n *\n * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.\n * @param {(String|Symbol)} evt The Event name.\n * @private\n */\nfunction clearEvent(emitter, evt) {\n if (--emitter._eventsCount === 0) emitter._events = new Events();\n else delete emitter._events[evt];\n}\n\n/**\n * Minimal `EventEmitter` interface that is molded against the Node.js\n * `EventEmitter` interface.\n *\n * @constructor\n * @public\n */\nfunction EventEmitter() {\n this._events = new Events();\n this._eventsCount = 0;\n}\n\n/**\n * Return an array listing the events for which the emitter has registered\n * listeners.\n *\n * @returns {Array}\n * @public\n */\nEventEmitter.prototype.eventNames = function eventNames() {\n var names = []\n , events\n , name;\n\n if (this._eventsCount === 0) return names;\n\n for (name in (events = this._events)) {\n if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);\n }\n\n if (Object.getOwnPropertySymbols) {\n return names.concat(Object.getOwnPropertySymbols(events));\n }\n\n return names;\n};\n\n/**\n * Return the listeners registered for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Array} The registered listeners.\n * @public\n */\nEventEmitter.prototype.listeners = function listeners(event) {\n var evt = prefix ? prefix + event : event\n , handlers = this._events[evt];\n\n if (!handlers) return [];\n if (handlers.fn) return [handlers.fn];\n\n for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {\n ee[i] = handlers[i].fn;\n }\n\n return ee;\n};\n\n/**\n * Return the number of listeners listening to a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Number} The number of listeners.\n * @public\n */\nEventEmitter.prototype.listenerCount = function listenerCount(event) {\n var evt = prefix ? prefix + event : event\n , listeners = this._events[evt];\n\n if (!listeners) return 0;\n if (listeners.fn) return 1;\n return listeners.length;\n};\n\n/**\n * Calls each of the listeners registered for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Boolean} `true` if the event had listeners, else `false`.\n * @public\n */\nEventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {\n var evt = prefix ? prefix + event : event;\n\n if (!this._events[evt]) return false;\n\n var listeners = this._events[evt]\n , len = arguments.length\n , args\n , i;\n\n if (listeners.fn) {\n if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);\n\n switch (len) {\n case 1: return listeners.fn.call(listeners.context), true;\n case 2: return listeners.fn.call(listeners.context, a1), true;\n case 3: return listeners.fn.call(listeners.context, a1, a2), true;\n case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;\n case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;\n case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;\n }\n\n for (i = 1, args = new Array(len -1); i < len; i++) {\n args[i - 1] = arguments[i];\n }\n\n listeners.fn.apply(listeners.context, args);\n } else {\n var length = listeners.length\n , j;\n\n for (i = 0; i < length; i++) {\n if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);\n\n switch (len) {\n case 1: listeners[i].fn.call(listeners[i].context); break;\n case 2: listeners[i].fn.call(listeners[i].context, a1); break;\n case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;\n case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;\n default:\n if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {\n args[j - 1] = arguments[j];\n }\n\n listeners[i].fn.apply(listeners[i].context, args);\n }\n }\n }\n\n return true;\n};\n\n/**\n * Add a listener for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} [context=this] The context to invoke the listener with.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.on = function on(event, fn, context) {\n return addListener(this, event, fn, context, false);\n};\n\n/**\n * Add a one-time listener for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} [context=this] The context to invoke the listener with.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.once = function once(event, fn, context) {\n return addListener(this, event, fn, context, true);\n};\n\n/**\n * Remove the listeners of a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn Only remove the listeners that match this function.\n * @param {*} context Only remove the listeners that have this context.\n * @param {Boolean} once Only remove one-time listeners.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {\n var evt = prefix ? prefix + event : event;\n\n if (!this._events[evt]) return this;\n if (!fn) {\n clearEvent(this, evt);\n return this;\n }\n\n var listeners = this._events[evt];\n\n if (listeners.fn) {\n if (\n listeners.fn === fn &&\n (!once || listeners.once) &&\n (!context || listeners.context === context)\n ) {\n clearEvent(this, evt);\n }\n } else {\n for (var i = 0, events = [], length = listeners.length; i < length; i++) {\n if (\n listeners[i].fn !== fn ||\n (once && !listeners[i].once) ||\n (context && listeners[i].context !== context)\n ) {\n events.push(listeners[i]);\n }\n }\n\n //\n // Reset the array, or remove it completely if we have no more listeners.\n //\n if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;\n else clearEvent(this, evt);\n }\n\n return this;\n};\n\n/**\n * Remove all listeners, or those of the specified event.\n *\n * @param {(String|Symbol)} [event] The event name.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {\n var evt;\n\n if (event) {\n evt = prefix ? prefix + event : event;\n if (this._events[evt]) clearEvent(this, evt);\n } else {\n this._events = new Events();\n this._eventsCount = 0;\n }\n\n return this;\n};\n\n//\n// Alias methods names because people roll like that.\n//\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\nEventEmitter.prototype.addListener = EventEmitter.prototype.on;\n\n//\n// Expose the prefix.\n//\nEventEmitter.prefixed = prefix;\n\n//\n// Allow `EventEmitter` to be imported as module namespace.\n//\nEventEmitter.EventEmitter = EventEmitter;\n\n//\n// Expose the module.\n//\nif (true) {\n module.exports = EventEmitter;\n}\n\n\n/***/ }),\n\n/***/ 2973:\n/***/ ((module) => {\n\n/**\n * @param {*} val - value to check\n * \n * @returns {boolean} true if the value is then-able\n */\nfunction isPromise(val) {\n return val != null && typeof val.then === 'function'\n}\n\n/**\n * @param {function} func - function to execute\n * @param {number|function(number):number} intervalLength - length in ms to wait before executing again\n * @param {{iterations: Infinity|number, stopOnError: boolean}} [options]\n * \n * @returns {Promise} Promise object with no result\n */\nfunction interval(func, intervalLength, options = {}) { \n\n validateArgs(func, intervalLength, options)\n\n const defaults = {\n iterations: Infinity,\n stopOnError: true\n }\n const settings = Object.assign(defaults, options)\n\n return new Promise((rootPromiseResolve, rootPromiseReject) => {\n\n const callFunction = currentIteration => {\n \n // Set up a way to track if a \"stop\" was requested by the user function\n let stopRequested = false\n const stop = () => {\n stopRequested = true\n }\n \n // Set up a function to call the next iteration. This is abstracted so it can be called by .then(), or in .catch(), if options allow.\n const callNext = () => {\n // If we've hit the desired number of iterations, or stop was called, resolve the root promise and return\n if (currentIteration === settings.iterations || stopRequested) {\n rootPromiseResolve()\n return\n }\n \n // Otherwise, call the next iteration\n callFunction(currentIteration + 1)\n }\n\n // Calculate our interval length\n const calculatedIntervalLength = (typeof intervalLength === 'function') ? intervalLength(currentIteration) : intervalLength\n \n // If the interval length was calculated, validate the result\n if (typeof intervalLength === 'function') {\n if (!Number.isInteger(calculatedIntervalLength) || calculatedIntervalLength < 0) {\n rootPromiseReject(new Error('Function for \"intervalLength\" argument must return a non-negative integer.'))\n return \n }\n }\n \n // Call the user function after the desired interval length. After, call the next iteration (and/or handle error)\n setTimeout(() => {\n\n const returnVal = func(currentIteration, stop)\n \n // Ensure that the value returned is a promise\n if (!isPromise(returnVal)) {\n rootPromiseReject(new Error('Return value of \"func\" must be a Promise.'))\n return\n }\n\n returnVal.then(callNext).catch(err => {\n if (!settings.stopOnError) {\n callNext()\n return\n }\n \n rootPromiseReject(err)\n })\n }, calculatedIntervalLength)\n }\n\n callFunction(1) \n })\n}\n\n/**\n * A helper function to validate the arguments passed to interval(...)\n * \n * @param {*} func \n * @param {*} intervalLength \n * @param {*} options\n */\nfunction validateArgs(func, intervalLength, options) {\n\n // Validate \"func\"\n if (typeof func !== 'function') {\n throw new TypeError('Argument 1, \"func\", must be a function.')\n }\n\n // Validate \"intervalLength\"\n if (typeof intervalLength === 'number') {\n if (!Number.isInteger(intervalLength) || intervalLength < 0) {\n throw new TypeError('Argument 2, \"intervalLength\", must be a non-negative integer or a function that returns a non-negative integer.')\n }\n } else if (typeof intervalLength !== 'function') {\n throw new TypeError('Argument 2, \"intervalLength\", must be a non-negative integer or a function that returns a non-negative integer.')\n }\n\n // Validate options...\n if (typeof options !== 'object') {\n throw new TypeError('Argument 3, \"options\", must be an object.')\n }\n\n // Validate passed keys\n const allowedKeys = ['iterations', 'stopOnError']\n\n Object.keys(options).forEach(key => {\n if (!allowedKeys.includes(key)) {\n throw new TypeError('Option \"' + key + '\" is not a valid option.')\n }\n })\n \n // validate \"iterations\" option (if passed)\n if (typeof options.iterations !== 'undefined') {\n if (options.iterations !== Infinity && (!Number.isInteger(options.iterations) || options.iterations < 1)) {\n throw new TypeError('Option \"iterations\" must be Infinity or an integer greater than 0.')\n }\n }\n \n // validate \"stopOnError\" option (if passed)\n if (typeof options.stopOnError !== 'undefined') {\n if (typeof options.stopOnError !== 'boolean') {\n throw new TypeError('Option \"stopOnError\" must be a boolean.')\n }\n }\n}\n\nmodule.exports = interval\n\n\n/***/ }),\n\n/***/ 9843:\n/***/ ((module) => {\n\n/**\n * Checks if `value` is `null` or `undefined`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is nullish, else `false`.\n * @example\n *\n * _.isNil(null);\n * // => true\n *\n * _.isNil(void 0);\n * // => true\n *\n * _.isNil(NaN);\n * // => false\n */\nfunction isNil(value) {\n return value == null;\n}\n\nmodule.exports = isNil;\n\n\n/***/ }),\n\n/***/ 7924:\n/***/ (function(module, __unused_webpack_exports, __nested_webpack_require_26904__) {\n\n/*******************************************************************************\n * Copyright (c) 2013 IBM Corp.\n *\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Eclipse Distribution License v1.0 which accompany this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n * and the Eclipse Distribution License is available at\n * http://www.eclipse.org/org/documents/edl-v10.php.\n *\n * Contributors:\n * Andrew Banks - initial API and implementation and initial documentation\n *******************************************************************************/\n\n\n// Only expose a single object name in the global namespace.\n// Everything must go through this module. Global Paho module\n// only has a single public function, client, which returns\n// a Paho client object given connection details.\n\n/**\n * Send and receive messages using web browsers.\n * <p>\n * This programming interface lets a JavaScript client application use the MQTT V3.1 or\n * V3.1.1 protocol to connect to an MQTT-supporting messaging server.\n *\n * The function supported includes:\n * <ol>\n * <li>Connecting to and disconnecting from a server. The server is identified by its host name and port number.\n * <li>Specifying options that relate to the communications link with the server,\n * for example the frequency of keep-alive heartbeats, and whether SSL/TLS is required.\n * <li>Subscribing to and receiving messages from MQTT Topics.\n * <li>Publishing messages to MQTT Topics.\n * </ol>\n * <p>\n * The API consists of two main objects:\n * <dl>\n * <dt><b>{@link Paho.Client}</b></dt>\n * <dd>This contains methods that provide the functionality of the API,\n * including provision of callbacks that notify the application when a message\n * arrives from or is delivered to the messaging server,\n * or when the status of its connection to the messaging server changes.</dd>\n * <dt><b>{@link Paho.Message}</b></dt>\n * <dd>This encapsulates the payload of the message along with various attributes\n * associated with its delivery, in particular the destination to which it has\n * been (or is about to be) sent.</dd>\n * </dl>\n * <p>\n * The programming interface validates parameters passed to it, and will throw\n * an Error containing an error message intended for developer use, if it detects\n * an error with any parameter.\n * <p>\n * Example:\n *\n * <code><pre>\nvar client = new Paho.MQTT.Client(location.hostname, Number(location.port), \"clientId\");\nclient.onConnectionLost = onConnectionLost;\nclient.onMessageArrived = onMessageArrived;\nclient.connect({onSuccess:onConnect});\n\nfunction onConnect() {\n // Once a connection has been made, make a subscription and send a message.\n console.log(\"onConnect\");\n client.subscribe(\"/World\");\n var message = new Paho.MQTT.Message(\"Hello\");\n message.destinationName = \"/World\";\n client.send(message);\n};\nfunction onConnectionLost(responseObject) {\n if (responseObject.errorCode !== 0)\n\tconsole.log(\"onConnectionLost:\"+responseObject.errorMessage);\n};\nfunction onMessageArrived(message) {\n console.log(\"onMessageArrived:\"+message.payloadString);\n client.disconnect();\n};\n * </pre></code>\n * @namespace Paho\n */\n\n/* jshint shadow:true */\n(function ExportLibrary(root, factory) {\n\tif(true){\n\t\tmodule.exports = factory();\n\t} else {}\n})(this, function LibraryFactory(){\n\n\n\tvar PahoMQTT = (function (global) {\n\n\t// Private variables below, these are only visible inside the function closure\n\t// which is used to define the module.\n\tvar version = \"@VERSION@-@BUILDLEVEL@\";\n\n\t/**\n\t * @private\n\t */\n\tvar localStorage = global.localStorage || (function () {\n\t\tvar data = {};\n\n\t\treturn {\n\t\t\tsetItem: function (key, item) { data[key] = item; },\n\t\t\tgetItem: function (key) { return data[key]; },\n\t\t\tremoveItem: function (key) { delete data[key]; },\n\t\t};\n\t})();\n\n\t\t/**\n\t * Unique message type identifiers, with associated\n\t * associated integer values.\n\t * @private\n\t */\n\t\tvar MESSAGE_TYPE = {\n\t\t\tCONNECT: 1,\n\t\t\tCONNACK: 2,\n\t\t\tPUBLISH: 3,\n\t\t\tPUBACK: 4,\n\t\t\tPUBREC: 5,\n\t\t\tPUBREL: 6,\n\t\t\tPUBCOMP: 7,\n\t\t\tSUBSCRIBE: 8,\n\t\t\tSUBACK: 9,\n\t\t\tUNSUBSCRIBE: 10,\n\t\t\tUNSUBACK: 11,\n\t\t\tPINGREQ: 12,\n\t\t\tPINGRESP: 13,\n\t\t\tDISCONNECT: 14\n\t\t};\n\n\t\t// Collection of utility methods used to simplify module code\n\t\t// and promote the DRY pattern.\n\n\t\t/**\n\t * Validate an object's parameter names to ensure they\n\t * match a list of expected variables name for this option\n\t * type. Used to ensure option object passed into the API don't\n\t * contain erroneous parameters.\n\t * @param {Object} obj - User options object\n\t * @param {Object} keys - valid keys and types that may exist in obj.\n\t * @throws {Error} Invalid option parameter found.\n\t * @private\n\t */\n\t\tvar validate = function(obj, keys) {\n\t\t\tfor (var key in obj) {\n\t\t\t\tif (obj.hasOwnProperty(key)) {\n\t\t\t\t\tif (keys.hasOwnProperty(key)) {\n\t\t\t\t\t\tif (typeof obj[key] !== keys[key])\n\t\t\t\t\t\t\tthrow new Error(format(ERROR.INVALID_TYPE, [typeof obj[key], key]));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar errorStr = \"Unknown property, \" + key + \". Valid properties are:\";\n\t\t\t\t\t\tfor (var validKey in keys)\n\t\t\t\t\t\t\tif (keys.hasOwnProperty(validKey))\n\t\t\t\t\t\t\t\terrorStr = errorStr+\" \"+validKey;\n\t\t\t\t\t\tthrow new Error(errorStr);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t/**\n\t * Return a new function which runs the user function bound\n\t * to a fixed scope.\n\t * @param {function} User function\n\t * @param {object} Function scope\n\t * @return {function} User function bound to another scope\n\t * @private\n\t */\n\t\tvar scope = function (f, scope) {\n\t\t\treturn function () {\n\t\t\t\treturn f.apply(scope, arguments);\n\t\t\t};\n\t\t};\n\n\t\t/**\n\t * Unique message type identifiers, with associated\n\t * associated integer values.\n\t * @private\n\t */\n\t\tvar ERROR = {\n\t\t\tOK: {code:0, text:\"AMQJSC0000I OK.\"},\n\t\t\tCONNECT_TIMEOUT: {code:1, text:\"AMQJSC0001E Connect timed out.\"},\n\t\t\tSUBSCRIBE_TIMEOUT: {code:2, text:\"AMQJS0002E Subscribe timed out.\"},\n\t\t\tUNSUBSCRIBE_TIMEOUT: {code:3, text:\"AMQJS0003E Unsubscribe timed out.\"},\n\t\t\tPING_TIMEOUT: {code:4, text:\"AMQJS0004E Ping timed out.\"},\n\t\t\tINTERNAL_ERROR: {code:5, text:\"AMQJS0005E Internal error. Error Message: {0}, Stack trace: {1}\"},\n\t\t\tCONNACK_RETURNCODE: {code:6, text:\"AMQJS0006E Bad Connack return code:{0} {1}.\"},\n\t\t\tSOCKET_ERROR: {code:7, text:\"AMQJS0007E Socket error:{0}.\"},\n\t\t\tSOCKET_CLOSE: {code:8, text:\"AMQJS0008I Socket closed.\"},\n\t\t\tMALFORMED_UTF: {code:9, text:\"AMQJS0009E Malformed UTF data:{0} {1} {2}.\"},\n\t\t\tUNSUPPORTED: {code:10, text:\"AMQJS0010E {0} is not supported by this browser.\"},\n\t\t\tINVALID_STATE: {code:11, text:\"AMQJS0011E Invalid state {0}.\"},\n\t\t\tINVALID_TYPE: {code:12, text:\"AMQJS0012E Invalid type {0} for {1}.\"},\n\t\t\tINVALID_ARGUMENT: {code:13, text:\"AMQJS0013E Invalid argument {0} for {1}.\"},\n\t\t\tUNSUPPORTED_OPERATION: {code:14, text:\"AMQJS0014E Unsupported operation.\"},\n\t\t\tINVALID_STORED_DATA: {code:15, text:\"AMQJS0015E Invalid data in local storage key={0} value={1}.\"},\n\t\t\tINVALID_MQTT_MESSAGE_TYPE: {code:16, text:\"AMQJS0016E Invalid MQTT message type {0}.\"},\n\t\t\tMALFORMED_UNICODE: {code:17, text:\"AMQJS0017E Malformed Unicode string:{0} {1}.\"},\n\t\t\tBUFFER_FULL: {code:18, text:\"AMQJS0018E Message buffer is full, maximum buffer size: {0}.\"},\n\t\t};\n\n\t\t/** CONNACK RC Meaning. */\n\t\tvar CONNACK_RC = {\n\t\t\t0:\"Connection Accepted\",\n\t\t\t1:\"Connection Refused: unacceptable protocol version\",\n\t\t\t2:\"Connection Refused: identifier rejected\",\n\t\t\t3:\"Connection Refused: server unavailable\",\n\t\t\t4:\"Connection Refused: bad user name or password\",\n\t\t\t5:\"Connection Refused: not authorized\"\n\t\t};\n\n\t/**\n\t * Format an error message text.\n\t * @private\n\t * @param {error} ERROR value above.\n\t * @param {substitutions} [array] substituted into the text.\n\t * @return the text with the substitutions made.\n\t */\n\t\tvar format = function(error, substitutions) {\n\t\t\tvar text = error.text;\n\t\t\tif (substitutions) {\n\t\t\t\tvar field,start;\n\t\t\t\tfor (var i=0; i<substitutions.length; i++) {\n\t\t\t\t\tfield = \"{\"+i+\"}\";\n\t\t\t\t\tstart = text.indexOf(field);\n\t\t\t\t\tif(start > 0) {\n\t\t\t\t\t\tvar part1 = text.substring(0,start);\n\t\t\t\t\t\tvar part2 = text.substring(start+field.length);\n\t\t\t\t\t\ttext = part1+substitutions[i]+part2;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn text;\n\t\t};\n\n\t\t//MQTT protocol and version 6 M Q I s d p 3\n\t\tvar MqttProtoIdentifierv3 = [0x00,0x06,0x4d,0x51,0x49,0x73,0x64,0x70,0x03];\n\t\t//MQTT proto/version for 311 4 M Q T T 4\n\t\tvar MqttProtoIdentifierv4 = [0x00,0x04,0x4d,0x51,0x54,0x54,0x04];\n\n\t\t/**\n\t * Construct an MQTT wire protocol message.\n\t * @param type MQTT packet type.\n\t * @param options optional wire message attributes.\n\t *\n\t * Optional properties\n\t *\n\t * messageIdentifier: message ID in the range [0..65535]\n\t * payloadMessage:\tApplication Message - PUBLISH only\n\t * connectStrings:\tarray of 0 or more Strings to be put into the CONNECT payload\n\t * topics:\t\t\tarray of strings (SUBSCRIBE, UNSUBSCRIBE)\n\t * requestQoS:\t\tarray of QoS values [0..2]\n\t *\n\t * \"Flag\" properties\n\t * cleanSession:\ttrue if present / false if absent (CONNECT)\n\t * willMessage: \ttrue if present / false if absent (CONNECT)\n\t * isRetained:\t\ttrue if present / false if absent (CONNECT)\n\t * userName:\t\ttrue if present / false if absent (CONNECT)\n\t * password:\t\ttrue if present / false if absent (CONNECT)\n\t * keepAliveInterval:\tinteger [0..65535] (CONNECT)\n\t *\n\t * @private\n\t * @ignore\n\t */\n\t\tvar WireMessage = function (type, options) {\n\t\t\tthis.type = type;\n\t\t\tfor (var name in options) {\n\t\t\t\tif (options.hasOwnProperty(name)) {\n\t\t\t\t\tthis[name] = options[name];\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tWireMessage.prototype.encode = function() {\n\t\t// Compute the first byte of the fixed header\n\t\t\tvar first = ((this.type & 0x0f) << 4);\n\n\t\t\t/*\n\t\t * Now calculate the length of the variable header + payload by adding up the lengths\n\t\t * of all the component parts\n\t\t */\n\n\t\t\tvar remLength = 0;\n\t\t\tvar topicStrLength = [];\n\t\t\tvar destinationNameLength = 0;\n\t\t\tvar willMessagePayloadBytes;\n\n\t\t\t// if the message contains a messageIdentifier then we need two bytes for that\n\t\t\tif (this.messageIdentifier !== undefined)\n\t\t\t\tremLength += 2;\n\n\t\t\tswitch(this.type) {\n\t\t\t// If this a Connect then we need to include 12 bytes for its header\n\t\t\tcase MESSAGE_TYPE.CONNECT:\n\t\t\t\tswitch(this.mqttVersion) {\n\t\t\t\tcase 3:\n\t\t\t\t\tremLength += MqttProtoIdentifierv3.length + 3;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 4:\n\t\t\t\t\tremLength += MqttProtoIdentifierv4.length + 3;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tremLength += UTF8Length(this.clientId) + 2;\n\t\t\t\tif (this.willMessage !== undefined) {\n\t\t\t\t\tremLength += UTF8Length(this.willMessage.destinationName) + 2;\n\t\t\t\t\t// Will message is always a string, sent as UTF-8 characters with a preceding length.\n\t\t\t\t\twillMessagePayloadBytes = this.willMessage.payloadBytes;\n\t\t\t\t\tif (!(willMessagePayloadBytes instanceof Uint8Array))\n\t\t\t\t\t\twillMessagePayloadBytes = new Uint8Array(payloadBytes);\n\t\t\t\t\tremLength += willMessagePayloadBytes.byteLength +2;\n\t\t\t\t}\n\t\t\t\tif (this.userName !== undefined)\n\t\t\t\t\tremLength += UTF8Length(this.userName) + 2;\n\t\t\t\tif (this.password !== undefined)\n\t\t\t\t\tremLength += UTF8Length(this.password) + 2;\n\t\t\t\tbreak;\n\n\t\t\t// Subscribe, Unsubscribe can both contain topic strings\n\t\t\tcase MESSAGE_TYPE.SUBSCRIBE:\n\t\t\t\tfirst |= 0x02; // Qos = 1;\n\t\t\t\tfor ( var i = 0; i < this.topics.length; i++) {\n\t\t\t\t\ttopicStrLength[i] = UTF8Length(this.topics[i]);\n\t\t\t\t\tremLength += topicStrLength[i] + 2;\n\t\t\t\t}\n\t\t\t\tremLength += this.requestedQos.length; // 1 byte for each topic's Qos\n\t\t\t\t// QoS on Subscribe only\n\t\t\t\tbreak;\n\n\t\t\tcase MESSAGE_TYPE.UNSUBSCRIBE:\n\t\t\t\tfirst |= 0x02; // Qos = 1;\n\t\t\t\tfor ( var i = 0; i < this.topics.length; i++) {\n\t\t\t\t\ttopicStrLength[i] = UTF8Length(this.topics[i]);\n\t\t\t\t\tremLength += topicStrLength[i] + 2;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase MESSAGE_TYPE.PUBREL:\n\t\t\t\tfirst |= 0x02; // Qos = 1;\n\t\t\t\tbreak;\n\n\t\t\tcase MESSAGE_TYPE.PUBLISH:\n\t\t\t\tif (this.payloadMessage.duplicate) first |= 0x08;\n\t\t\t\tfirst = first |= (this.payloadMessage.qos << 1);\n\t\t\t\tif (this.payloadMessage.retained) first |= 0x01;\n\t\t\t\tdestinationNameLength = UTF8Length(this.payloadMessage.destinationName);\n\t\t\t\tremLength += destinationNameLength + 2;\n\t\t\t\tvar payloadBytes = this.payloadMessage.payloadBytes;\n\t\t\t\tremLength += payloadBytes.byteLength;\n\t\t\t\tif (payloadBytes instanceof ArrayBuffer)\n\t\t\t\t\tpayloadBytes = new Uint8Array(payloadBytes);\n\t\t\t\telse if (!(payloadBytes instanceof Uint8Array))\n\t\t\t\t\tpayloadBytes = new Uint8Array(payloadBytes.buffer);\n\t\t\t\tbreak;\n\n\t\t\tcase MESSAGE_TYPE.DISCONNECT:\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Now we can allocate a buffer for the message\n\n\t\t\tvar mbi = encodeMBI(remLength); // Convert the length to MQTT MBI format\n\t\t\tvar pos = mbi.length + 1; // Offset of start of variable header\n\t\t\tvar buffer = new ArrayBuffer(remLength + pos);\n\t\t\tvar byteStream = new Uint8Array(buffer); // view it as a sequence of bytes\n\n\t\t\t//Write the fixed header into the buffer\n\t\t\tbyteStream[0] = first;\n\t\t\tbyteStream.set(mbi,1);\n\n\t\t\t// If this is a PUBLISH then the variable header starts with a topic\n\t\t\tif (this.type == MESSAGE_TYPE.PUBLISH)\n\t\t\t\tpos = writeString(this.payloadMessage.destinationName, destinationNameLength, byteStream, pos);\n\t\t\t// If this is a CONNECT then the variable header contains the protocol name/version, flags and keepalive time\n\n\t\t\telse if (this.type == MESSAGE_TYPE.CONNECT) {\n\t\t\t\tswitch (this.mqttVersion) {\n\t\t\t\tcase 3:\n\t\t\t\t\tbyteStream.set(MqttProtoIdentifierv3, pos);\n\t\t\t\t\tpos += MqttProtoIdentifierv3.length;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 4:\n\t\t\t\t\tbyteStream.set(MqttProtoIdentifierv4, pos);\n\t\t\t\t\tpos += MqttProtoIdentifierv4.length;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tvar connectFlags = 0;\n\t\t\t\tif (this.cleanSession)\n\t\t\t\t\tconnectFlags = 0x02;\n\t\t\t\tif (this.willMessage !== undefined ) {\n\t\t\t\t\tconnectFlags |= 0x04;\n\t\t\t\t\tconnectFlags |= (this.willMessage.qos<<3);\n\t\t\t\t\tif (this.willMessage.retained) {\n\t\t\t\t\t\tconnectFlags |= 0x20;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (this.userName !== undefined)\n\t\t\t\t\tconnectFlags |= 0x80;\n\t\t\t\tif (this.password !== undefined)\n\t\t\t\t\tconnectFlags |= 0x40;\n\t\t\t\tbyteStream[pos++] = connectFlags;\n\t\t\t\tpos = writeUint16 (this.keepAliveInterval, byteStream, pos);\n\t\t\t}\n\n\t\t\t// Output the messageIdentifier - if there is one\n\t\t\tif (this.messageIdentifier !== undefined)\n\t\t\t\tpos = writeUint16 (this.messageIdentifier, byteStream, pos);\n\n\t\t\tswitch(this.type) {\n\t\t\tcase MESSAGE_TYPE.CONNECT:\n\t\t\t\tpos = writeString(this.clientId, UTF8Length(this.clientId), byteStream, pos);\n\t\t\t\tif (this.willMessage !== undefined) {\n\t\t\t\t\tpos = writeString(this.willMessage.destinationName, UTF8Length(this.willMessage.destinationName), byteStream, pos);\n\t\t\t\t\tpos = writeUint16(willMessagePayloadBytes.byteLength, byteStream, pos);\n\t\t\t\t\tbyteStream.set(willMessagePayloadBytes, pos);\n\t\t\t\t\tpos += willMessagePayloadBytes.byteLength;\n\n\t\t\t\t}\n\t\t\t\tif (this.userName !== undefined)\n\t\t\t\t\tpos = writeString(this.userName, UTF8Length(this.userName), byteStream, pos);\n\t\t\t\tif (this.password !== undefined)\n\t\t\t\t\tpos = writeString(this.password, UTF8Length(this.password), byteStream, pos);\n\t\t\t\tbreak;\n\n\t\t\tcase MESSAGE_TYPE.PUBLISH:\n\t\t\t\t// PUBLISH has a text or binary payload, if text do not add a 2 byte length field, just the UTF characters.\n\t\t\t\tbyteStream.set(payloadBytes, pos);\n\n\t\t\t\tbreak;\n\n\t\t\t\t// \t case MESSAGE_TYPE.PUBREC:\n\t\t\t\t// \t case MESSAGE_TYPE.PUBREL:\n\t\t\t\t// \t case MESSAGE_TYPE.PUBCOMP:\n\t\t\t\t// \t \tbreak;\n\n\t\t\tcase MESSAGE_TYPE.SUBSCRIBE:\n\t\t\t\t// SUBSCRIBE has a list of topic strings and request QoS\n\t\t\t\tfor (var i=0; i<this.topics.length; i++) {\n\t\t\t\t\tpos = writeString(this.topics[i], topicStrLength[i], byteStream, pos);\n\t\t\t\t\tbyteStream[pos++] = this.requestedQos[i];\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase MESSAGE_TYPE.UNSUBSCRIBE:\n\t\t\t\t// UNSUBSCRIBE has a list of topic strings\n\t\t\t\tfor (var i=0; i<this.topics.length; i++)\n\t\t\t\t\tpos = writeString(this.topics[i], topicStrLength[i], byteStream, pos);\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\t// Do nothing.\n\t\t\t}\n\n\t\t\treturn buffer;\n\t\t};\n\n\t\tfunction decodeMessage(input,pos) {\n\t\t\tvar startingPos = pos;\n\t\t\tvar first = input[pos];\n\t\t\tvar type = first >> 4;\n\t\t\tvar messageInfo = first &= 0x0f;\n\t\t\tpos += 1;\n\n\n\t\t\t// Decode the remaining length (MBI format)\n\n\t\t\tvar digit;\n\t\t\tvar remLength = 0;\n\t\t\tvar multiplier = 1;\n\t\t\tdo {\n\t\t\t\tif (pos == input.length) {\n\t\t\t\t\treturn [null,startingPos];\n\t\t\t\t}\n\t\t\t\tdigit = input[pos++];\n\t\t\t\tremLength += ((digit & 0x7F) * multiplier);\n\t\t\t\tmultiplier *= 128;\n\t\t\t} while ((digit & 0x80) !== 0);\n\n\t\t\tvar endPos = pos+remLength;\n\t\t\tif (endPos > input.length) {\n\t\t\t\treturn [null,startingPos];\n\t\t\t}\n\n\t\t\tvar wireMessage = new WireMessage(type);\n\t\t\tswitch(type) {\n\t\t\tcase MESSAGE_TYPE.CONNACK:\n\t\t\t\tvar connectAcknowledgeFlags = input[pos++];\n\t\t\t\tif (connectAcknowledgeFlags & 0x01)\n\t\t\t\t\twireMessage.sessionPresent = true;\n\t\t\t\twireMessage.returnCode = input[pos++];\n\t\t\t\tbreak;\n\n\t\t\tcase MESSAGE_TYPE.PUBLISH:\n\t\t\t\tvar qos = (messageInfo >> 1) & 0x03;\n\n\t\t\t\tvar len = readUint16(input, pos);\n\t\t\t\tpos += 2;\n\t\t\t\tvar topicName = parseUTF8(input, pos, len);\n\t\t\t\tpos += len;\n\t\t\t\t// If QoS 1 or 2 there will be a messageIdentifier\n\t\t\t\tif (qos > 0) {\n\t\t\t\t\twireMessage.messageIdentifier = readUint16(input, pos);\n\t\t\t\t\tpos += 2;\n\t\t\t\t}\n\n\t\t\t\tvar message = new Message(input.subarray(pos, endPos));\n\t\t\t\tif ((messageInfo & 0x01) == 0x01)\n\t\t\t\t\tmessage.retained = true;\n\t\t\t\tif ((messageInfo & 0x08) == 0x08)\n\t\t\t\t\tmessage.duplicate = true;\n\t\t\t\tmessage.qos = qos;\n\t\t\t\tmessage.destinationName = topicName;\n\t\t\t\twireMessage.payloadMessage = message;\n\t\t\t\tbreak;\n\n\t\t\tcase MESSAGE_TYPE.PUBACK:\n\t\t\tcase MESSAGE_TYPE.PUBREC:\n\t\t\tcase MESSAGE_TYPE.PUBREL:\n\t\t\tcase MESSAGE_TYPE.PUBCOMP:\n\t\t\tcase MESSAGE_TYPE.UNSUBACK:\n\t\t\t\twireMessage.messageIdentifier = readUint16(input, pos);\n\t\t\t\tbreak;\n\n\t\t\tcase MESSAGE_TYPE.SUBACK:\n\t\t\t\twireMessage.messageIdentifier = readUint16(input, pos);\n\t\t\t\tpos += 2;\n\t\t\t\twireMessage.returnCode = input.subarray(pos, endPos);\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\treturn [wireMessage,endPos];\n\t\t}\n\n\t\tfunction writeUint16(input, buffer, offset) {\n\t\t\tbuffer[offset++] = input >> 8; //MSB\n\t\t\tbuffer[offset++] = input % 256; //LSB\n\t\t\treturn offset;\n\t\t}\n\n\t\tfunction writeString(input, utf8Length, buffer, offset) {\n\t\t\toffset = writeUint16(utf8Length, buffer, offset);\n\t\t\tstringToUTF8(input, buffer, offset);\n\t\t\treturn offset + utf8Length;\n\t\t}\n\n\t\tfunction readUint16(buffer, offset) {\n\t\t\treturn 256*buffer[offset] + buffer[offset+1];\n\t\t}\n\n\t\t/**\n\t * Encodes an MQTT Multi-Byte Integer\n\t * @private\n\t */\n\t\tfunction encodeMBI(number) {\n\t\t\tvar output = new Array(1);\n\t\t\tvar numBytes = 0;\n\n\t\t\tdo {\n\t\t\t\tvar digit = number % 128;\n\t\t\t\tnumber = number >> 7;\n\t\t\t\tif (number > 0) {\n\t\t\t\t\tdigit |= 0x80;\n\t\t\t\t}\n\t\t\t\toutput[numBytes++] = digit;\n\t\t\t} while ( (number > 0) && (numBytes<4) );\n\n\t\t\treturn output;\n\t\t}\n\n\t\t/**\n\t * Takes a String and calculates its length in bytes when encoded in UTF8.\n\t * @private\n\t */\n\t\tfunction UTF8Length(input) {\n\t\t\tvar output = 0;\n\t\t\tfor (var i = 0; i<input.length; i++)\n\t\t\t{\n\t\t\t\tvar charCode = input.charCodeAt(i);\n\t\t\t\tif (charCode > 0x7FF)\n\t\t\t\t{\n\t\t\t\t\t// Surrogate pair means its a 4 byte character\n\t\t\t\t\tif (0xD800 <= charCode && charCode <= 0xDBFF)\n\t\t\t\t\t{\n\t\t\t\t\t\ti++;\n\t\t\t\t\t\toutput++;\n\t\t\t\t\t}\n\t\t\t\t\toutput +=3;\n\t\t\t\t}\n\t\t\t\telse if (charCode > 0x7F)\n\t\t\t\t\toutput +=2;\n\t\t\t\telse\n\t\t\t\t\toutput++;\n\t\t\t}\n\t\t\treturn output;\n\t\t}\n\n\t\t/**\n\t * Takes a String and writes it into an array as UTF8 encoded bytes.\