UNPKG

hbbtv-lib

Version:

Library for common functionality needed in HbbTV applications.

871 lines (779 loc) 27.3 kB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["cs_manager"] = factory(); else root["hbbtvLib"] = root["hbbtvLib"] || {}, root["hbbtvLib"]["src"] = root["hbbtvLib"]["src"] || {}, root["hbbtvLib"]["src"]["cs"] = root["hbbtvLib"]["src"]["cs"] || {}, root["hbbtvLib"]["src"]["cs"]["cs_manager"] = factory(); })(typeof self !== 'undefined' ? self : this, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports, __webpack_require__) { /* * Copyright: IRT 2019 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var Emitter = __webpack_require__(1).EventEmitter; var inherit = __webpack_require__(2); var instance = null; /** * Instances of this class provide details of endpoints of a Terminal that has * been discovered using the discoverTerminals() * * @typedef {object} DiscoveredCSLauncher * @property {number} enum_id The unique ID of an instance of a CS Launcher application. * @property {number} friendly_name A CS Launcher application may provide a friendly name. * @property {number} CS_OS_id The CS OS identifier string, as described in clause 14.4.1. of the HbbTV 2 specification */ /** * An error occured. * * <p>Use the [CSMan.EVT_CS_ERROR]{@link CSMan#EVT_CS_ERROR} event name constant * to listen for this event. * * @event CSMan#EVT_CS_ERROR * @param {string} errorCode Error code. Following values possible: * <ul> * <li>[ERR_UNDEFINED]{@link CSMan#ERR_UNDEFINED} * <li>[ERR_CSMAN_NOTFOUND]{@link CSMan#ERR_CSMAN_NOTFOUND} * <li>[ERR_INVALID_ENUM_ID]{@link CSMan#ERR_INVALID_ENUM_ID} * <li>[ERR_CSMAN_TIMEOUT]{@link CSMan#ERR_CSMAN_TIMEOUT} * </ul> * @param {string} message A textual description of what happened */ /** * A companion screen has been discovered or the discovery timed out. * * <p>Use the [CSMan.EVT_CS_DISCOVERED]{@link CSMan#EVT_CS_DISCOVERED} event name constant * to listen for this event. * * @event CSMan#EVT_CS_DISCOVERED * @param {Array<DiscoveredCSLauncher>} csLaunchers Array of discovered CS launchers. */ /** * Response of a launch or install request is available. * * @event CSMan#EVT_CS_LAUNCH_RESPONSE * @param {number} responseCode Can have the following values: * <ul> * <li>[OP_REJECTED]{@link CSMan#OP_REJECTED} * <li>[OP_DENIED]{@link CSMan#OP_DENIED} * <li>[INVALID_ID]{@link CSMan#INVALID_ID} * <li>[GENERAL_ERROR]{@link CSMan#GENERAL_ERROR} * <li>[OP_FAILED]{@link CSMan#OP_FAILED} * <li>[APP_ALREADY_INSTALLED]{@link CSMan#APP_ALREADY_INSTALLED} * </ul> */ /** * @exports CSMan * @class CSMan * @hideconstructor * * @classdesc Module for using the Companion Screen Manager API of HbbTV 2.0 * * <p>CSMan may fire the following events: * <ul> * <li>[EVT_CS_ERROR]{@link CSMan#event:EVT_CS_ERROR}</li> * <li>[EVT_CS_DISCOVERED]{@link CSMan#event:EVT_CS_DISCOVERED}</li> * <li>[EVT_CS_LAUNCH_RESPONSE]{@link CSMan#event:EVT_CS_LAUNCH_RESPONSE}</li> * </ul> * * @example <caption>Launch a webpage with the remote app2app service endpoint added to the URL.</caption> * var CSMan = require("hbbtv-lib/cs/cs_manager"); * * CSMan.once(CSMan.CS_DISCOVERED, on_discovery_finished); * CSMan.discover_launchers(10000); * * function on_discovery_finished (devices) { * for (x in devices) { * CSMan.launch_html(devices[x].enum_id, "http://example.com/"); * } * } * * @augments external:EventEmitter */ function CSMan () { try { this.cs_man = oipfObjectFactory.createCSManager(); if (!this.cs_man || typeof this.cs_man.discoverCSLaunchers != "function") { this.cs_man = null; } } catch (e) { } } inherit(CSMan, Emitter); /** * Get the current base URL of the local endpoint of the application to application * communication service. * * <p>The endpoint is defined in clause 14.5.2 of the * [HbbTV 2 specification]{@link https://www.hbbtv.org/wp-content/uploads/2018/02/HbbTV_v202_specification_2018_02_16.pdf}. * The usage of this endpoint to communicate between the HbbTV® application and the * remote client is described in clause 14.5.1. The URL retrieved by this method shall * end with a slash ('/') character. * * @returns {string} the local app2app service endpoint. */ CSMan.prototype.getA2A_local = function () { try { return this.cs_man.getApp2AppLocalBaseURL(); } catch (e) {} return null; }; /** * Get the current base URL of the remote endpoint of the application to application service. * * <p>The URL retrieved by this method shall be the same as the URL carried * in the <X_HbbTV_App2AppURL> element as described in clause 14.7.2 of the * [HbbTV 2 specification]{@link https://www.hbbtv.org/wp-content/uploads/2018/02/HbbTV_v202_specification_2018_02_16.pdf} * and shall end with a slash ('/') character. * * @returns {string} the remote app2app service endpoint, i.e. the one used by the companion application */ CSMan.prototype.getA2A_remote = function () { try { return this.cs_man.getApp2AppRemoteBaseURL(); } catch (e) {} return null; } /** * Get the URL that points to the CSS-CII service endpoint of the terminal that the calling * HbbTV application is running on. * * <p>The URL retrieved by this method shall be the same as the URL carried in the * <X_HbbTV_InterDevSyncURL> element as described in clause 14.7.2. of the * [HbbTV 2 specification]{@link https://www.hbbtv.org/wp-content/uploads/2018/02/HbbTV_v202_specification_2018_02_16.pdf} * * @returns {string} the DVB CSS CII service endpoint. */ CSMan.prototype.getCII = function () { try { return this.cs_man.getInterDevSyncURL (); } catch (e) {} return null; } /** * Discovers available CS launchers. * * @param {number} [timeout=1500] Specifies when discovery shall terminate. * * @fires CSMan#EVT_CS_DISCOVERED * @fires CSMan#EVT_CS_ERROR */ CSMan.prototype.discover_launchers = function (timeout) { var _timeout = timeout || 1500; var timer = null; var that = this; if (this.cs_man && this.cs_man.discoverCSLaunchers(function (arr) { if (timer) { clearTimeout(timer); timer = null; that.emit(that.EVT_CS_DISCOVERED, arr); } else { that.emit(that.EVT_CS_ERROR, that.ERR_UNDEFINED, "CS Manager: onCSDiscovery called after time out."); } })) { timer = setTimeout ( function () { timer = null; that.emit(that.EVT_CS_ERROR, that.ERR_CSMAN_TIMEOUT, "CS Manager: discovery timed out."); }, _timeout ); return true; } else { this.emit(this.EVT_CS_ERROR, this.ERR_CSMAN_NOTFOUND, "CSManager not available."); return false; } } /** * Send launch and install requests. * * @param {number} enum_id Identifier (enum_id) of a [DiscoveredCSLauncher]{@link DiscoveredCSLauncher} * @param {string} payload Information on the app to be launched. * * @returns {boolean} TRUE if request was executed, else FALSE. * * @fires CSMan#EVT_CS_LAUNCH_RESPONSE * @fires CSMan#EVT_CS_ERROR * * @see Section 14.4.2. of the [HbbTV 2 specification]{@link https://www.hbbtv.org/wp-content/uploads/2018/02/HbbTV_v202_specification_2018_02_16.pdf} * for the definition of the payload format. */ CSMan.prototype.send_request = function (enum_id, request) { var that = this; if (this.cs_man.launchCSApp(enum_id, request, function (enum_id, error_code) { that.emit(that.EVT_CS_LAUNCH_RESPONSE, enum_id, error_code); } )) { return true; } this.emit(this.EVT_CS_ERROR, this.ERR_INVALID_ENUM_ID, enum_id, "CSManager: launch failed, enum_id not valid: " + enum_id); return false; } CSMan.prototype.to_launch_struct = function (url, type) { return {"launchUrl": url, "appType": type}; } /** * Launches an HTML page on the selected device. * * @param {number} enum_id Identifier (enum_id) of a [DiscoveredCSLauncher]{@link DiscoveredCSLauncher} * @param {string} url a URL to a web site that shall be launched. * * @returns {boolean} TRUE if request was executed, else FALSE. * * @fires CSMan#EVT_CS_LAUNCH_RESPONSE * @fires CSMan#EVT_CS_ERROR */ CSMan.prototype.launch_html = function (enum_id, url) { if (!this.cs_man) { this.emit(this.CS_ERROR, this.ERR_CSMAN_NOTFOUND, "CSManager not available."); return false; } return this.send_request(enum_id, JSON.stringify( { "launch": [this.to_launch_struct(url, "html")] } )); } /** * Launches a native application on the selected device. * * @param {number} enum_id Identifier (enum_id) of a [DiscoveredCSLauncher]{@link DiscoveredCSLauncher} * @param {string} url a URL that is connected with a native application, that is installed on the companion device. * * @returns {boolean} TRUE if request was executed, else FALSE. * * @fires CSMan#EVT_CS_LAUNCH_RESPONSE * @fires CSMan#EVT_CS_ERROR */ CSMan.prototype.launch_native = function (enum_id, url) { if (!this.cs_man) { this.emit(this.CS_ERROR, this.ERR_CSMAN_NOTFOUND, "CSManager not available."); return false; } return this.send_request(enum_id, JSON.stringify( { "launch": [this.to_launch_struct(url, "native")] } )); } /** * Launches a native application with an HTML page as fallback on the selected device. * * @param {number} enum_id Identifier (enum_id) of a [DiscoveredCSLauncher]{@link DiscoveredCSLauncher} * @param {string} url_native a URL that is connected with a native application, that is installed on the companion device. * @param {string} url_html a URL to a web site that shall be launched if the native application can't be launched. * * @returns {boolean} TRUE if request was executed, else FALSE. * * @fires CSMan#EVT_CS_LAUNCH_RESPONSE * @fires CSMan#EVT_CS_ERROR */ CSMan.prototype.launch_native_html = function (enum_id, url_native, url_html) { if (!this.cs_man) { this.emit(this.CS_ERROR, this.ERR_CSMAN_NOTFOUND, "CSManager not available."); return false; } return this.send_request(enum_id, JSON.stringify( { "launch": [ this.to_launch_struct(url_native, "native"), this.to_launch_struct(url_html, "html") ] } )); } /** * Issues an install request on the selected device. * * @param {number} enum_id Identifier (enum_id) of a [DiscoveredCSLauncher]{@link DiscoveredCSLauncher} * @param {string} app_url market specific identifier of an application * @param {string} market_id id of a supported market on the companion device, e.g. Play Store, etc. * * * @returns {boolean} TRUE if request was executed, else FALSE. * * @fires CSMan#EVT_CS_LAUNCH_RESPONSE * @fires CSMan#EVT_CS_ERROR */ CSMan.prototype.install = function (enum_id, app_url, market_id) { if (!this.cs_man) { this.emit(this.CS_ERROR, this.ERR_CSMAN_NOTFOUND, "CSManager not available."); return false; } return this.send_request(enum_id, JSON.stringify( { "install": [ { "installUrl" : app_url, "appStoreId" : market_id } ] } )); } /** * Event name constant for the [EVT_CS_ERROR]{@link CSMan#event:EVT_CS_ERROR} event. */ CSMan.prototype.EVT_CS_ERROR = "error"; CSMan.prototype.CS_ERROR = CSMan.prototype.EVT_CS_ERROR; // Backward compatibility /** * Event name constant for the [EVT_CS_DISCOVERED]{@link CSMan#event:EVT_CS_DISCOVERED} event. */ CSMan.prototype.EVT_CS_DISCOVERED = "cs_discovered"; CSMan.prototype.CS_DISCOVERED = CSMan.prototype.EVT_CS_DISCOVERED; // Backward compatibility /** * Event name constant for the [EVT_CS_LAUNCH_RESPONSE]{@link CSMan#event:EVT_CS_LAUNCH_RESPONSE} event. */ CSMan.prototype.EVT_CS_LAUNCH_RESPONSE = "cs_launch_resp"; CSMan.prototype.CS_LAUNCH_RESPONSE = CSMan.prototype.EVT_CS_LAUNCH_RESPONSE; /** * Unspecified error. */ CSMan.prototype.ERR_UNDEFINED = 0; /** * HbbTV CS Manager could not be initialized. */ CSMan.prototype.ERR_CSMAN_NOTFOUND = 1; /** * Error signalled if the enum_id in a launch or install request does not match a connected CS launcher. */ CSMan.prototype.ERR_INVALID_ENUM_ID = 2; /** * The discovery for launcher apps timed out. HbbTV requires that the discovery is finished within a second. * @see CSMan.discover_launchers() */ CSMan.prototype.ERR_CSMAN_TIMEOUT = 3; // Error codes fuer launch_and_install /** * The CS Launcher application has automatically rejected * the operation with no interaction with the user of the * Companion Screen. * This error code is intended for use when the CS Launcher * has automatically blocked the operation due to a blacklist * feature. */ CSMan.prototype.OP_REJECTED = 0; /** * The CS Launcher application has blocked the operation, * but it was blocked by the explicit interaction of the user of * the Companion Screen. */ CSMan.prototype.OP_DENIED = 1; /** * The CS Launcher application has initiated the instruction * (launch or install) without a problem. It is assumed (to the * best knowledge of the Launcher application) that the * launch or installation operation has completed * successfully. */ CSMan.prototype.OP_NOT_GUARANTEED = 2; /** * The CS Launcher application that is identified by enum_id * is no longer available. (i.e. it has become unavailable * since discovery occurred), or has never been available. */ CSMan.prototype.INVALID_ID = 3; /** * A general error has occurred that meant that the operation * could not be completed for a reason other than those * described for the other error codes in this table. */ CSMan.prototype.GENERAL_ERROR = 4; /** * The CS Launcher application attempted a Launch or * Install operation but it is known to have failed. For a Native * application, it means that the application could not be * launched or installed. For an HTML application it means * that an HTML application environment could not be * launched. */ CSMan.prototype.OP_FAILED = 5; /** * The CS Launcher application received an Install operation * (without a Launch operation) but it detected that the * requested application is already installed */ CSMan.prototype.APP_ALREADY_INSTALLED = 6; module.exports = { getInstance : function () { if (instance === null) { instance = new CSMan(); } return instance; } }; /***/ }), /* 1 */ /***/ (function(module, exports) { // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. function EventEmitter() { this._events = this._events || {}; this._maxListeners = this._maxListeners || undefined; } module.exports = EventEmitter; // Backwards-compat with node 0.10.x EventEmitter.EventEmitter = EventEmitter; EventEmitter.prototype._events = undefined; EventEmitter.prototype._maxListeners = undefined; // By default EventEmitters will print a warning if more than 10 listeners are // added to it. This is a useful default which helps finding memory leaks. EventEmitter.defaultMaxListeners = 10; // Obviously not all Emitters should be limited to 10. This function allows // that to be increased. Set to zero for unlimited. EventEmitter.prototype.setMaxListeners = function(n) { if (!isNumber(n) || n < 0 || isNaN(n)) throw TypeError('n must be a positive number'); this._maxListeners = n; return this; }; EventEmitter.prototype.emit = function(type) { var er, handler, len, args, i, listeners; if (!this._events) this._events = {}; // If there is no 'error' event listener then throw. if (type === 'error') { if (!this._events.error || (isObject(this._events.error) && !this._events.error.length)) { er = arguments[1]; if (er instanceof Error) { throw er; // Unhandled 'error' event } else { // At least give some kind of context to the user var err = new Error('Uncaught, unspecified "error" event. (' + er + ')'); err.context = er; throw err; } } } handler = this._events[type]; if (isUndefined(handler)) return false; if (isFunction(handler)) { switch (arguments.length) { // fast cases case 1: handler.call(this); break; case 2: handler.call(this, arguments[1]); break; case 3: handler.call(this, arguments[1], arguments[2]); break; // slower default: args = Array.prototype.slice.call(arguments, 1); handler.apply(this, args); } } else if (isObject(handler)) { args = Array.prototype.slice.call(arguments, 1); listeners = handler.slice(); len = listeners.length; for (i = 0; i < len; i++) listeners[i].apply(this, args); } return true; }; EventEmitter.prototype.addListener = function(type, listener) { var m; if (!isFunction(listener)) throw TypeError('listener must be a function'); if (!this._events) this._events = {}; // To avoid recursion in the case that type === "newListener"! Before // adding it to the listeners, first emit "newListener". if (this._events.newListener) this.emit('newListener', type, isFunction(listener.listener) ? listener.listener : listener); if (!this._events[type]) // Optimize the case of one listener. Don't need the extra array object. this._events[type] = listener; else if (isObject(this._events[type])) // If we've already got an array, just append. this._events[type].push(listener); else // Adding the second element, need to change to array. this._events[type] = [this._events[type], listener]; // Check for listener leak if (isObject(this._events[type]) && !this._events[type].warned) { if (!isUndefined(this._maxListeners)) { m = this._maxListeners; } else { m = EventEmitter.defaultMaxListeners; } if (m && m > 0 && this._events[type].length > m) { this._events[type].warned = true; console.error('(node) warning: possible EventEmitter memory ' + 'leak detected. %d listeners added. ' + 'Use emitter.setMaxListeners() to increase limit.', this._events[type].length); if (typeof console.trace === 'function') { // not supported in IE 10 console.trace(); } } } return this; }; EventEmitter.prototype.on = EventEmitter.prototype.addListener; EventEmitter.prototype.once = function(type, listener) { if (!isFunction(listener)) throw TypeError('listener must be a function'); var fired = false; function g() { this.removeListener(type, g); if (!fired) { fired = true; listener.apply(this, arguments); } } g.listener = listener; this.on(type, g); return this; }; // emits a 'removeListener' event iff the listener was removed EventEmitter.prototype.removeListener = function(type, listener) { var list, position, length, i; if (!isFunction(listener)) throw TypeError('listener must be a function'); if (!this._events || !this._events[type]) return this; list = this._events[type]; length = list.length; position = -1; if (list === listener || (isFunction(list.listener) && list.listener === listener)) { delete this._events[type]; if (this._events.removeListener) this.emit('removeListener', type, listener); } else if (isObject(list)) { for (i = length; i-- > 0;) { if (list[i] === listener || (list[i].listener && list[i].listener === listener)) { position = i; break; } } if (position < 0) return this; if (list.length === 1) { list.length = 0; delete this._events[type]; } else { list.splice(position, 1); } if (this._events.removeListener) this.emit('removeListener', type, listener); } return this; }; EventEmitter.prototype.removeAllListeners = function(type) { var key, listeners; if (!this._events) return this; // not listening for removeListener, no need to emit if (!this._events.removeListener) { if (arguments.length === 0) this._events = {}; else if (this._events[type]) delete this._events[type]; return this; } // emit removeListener for all listeners on all events if (arguments.length === 0) { for (key in this._events) { if (key === 'removeListener') continue; this.removeAllListeners(key); } this.removeAllListeners('removeListener'); this._events = {}; return this; } listeners = this._events[type]; if (isFunction(listeners)) { this.removeListener(type, listeners); } else if (listeners) { // LIFO order while (listeners.length) this.removeListener(type, listeners[listeners.length - 1]); } delete this._events[type]; return this; }; EventEmitter.prototype.listeners = function(type) { var ret; if (!this._events || !this._events[type]) ret = []; else if (isFunction(this._events[type])) ret = [this._events[type]]; else ret = this._events[type].slice(); return ret; }; EventEmitter.prototype.listenerCount = function(type) { if (this._events) { var evlistener = this._events[type]; if (isFunction(evlistener)) return 1; else if (evlistener) return evlistener.length; } return 0; }; EventEmitter.listenerCount = function(emitter, type) { return emitter.listenerCount(type); }; function isFunction(arg) { return typeof arg === 'function'; } function isNumber(arg) { return typeof arg === 'number'; } function isObject(arg) { return typeof arg === 'object' && arg !== null; } function isUndefined(arg) { return arg === void 0; } /***/ }), /* 2 */ /***/ (function(module, exports) { /* * Copyright: IRT 2019 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ if (typeof Object.create !== 'function') { Object.create = function (o) { function F() {} F.prototype = o; return new F(); }; } /** * Copies prototype from B to A, i.e. A extends/inherits B. * * @param {*} A child "class" * @param {*} B parent "class" * * @ignore */ function inherit (A, B) { if (typeof (A.prototype) == "object" && typeof (B.prototype) == "object") { A.prototype = Object.create(B.prototype); } } module.exports = inherit; /***/ }) /******/ ]); });