UNPKG

matrix-engine

Version:

basic_timeline improved, VT func setup vide html element id with name arg.- DISABLE RAYCAST DEBUG TEST [2.3.3] Fix for GUI win desktop [2.3.0] DestrucMesh solution & loading convex objs for physics BASIC, SpriteAnimation CPU/texture solution added, Improv

1,335 lines (1,192 loc) 1.71 MB
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,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. 'use strict'; var R = typeof Reflect === 'object' ? Reflect : null var ReflectApply = R && typeof R.apply === 'function' ? R.apply : function ReflectApply(target, receiver, args) { return Function.prototype.apply.call(target, receiver, args); } var ReflectOwnKeys if (R && typeof R.ownKeys === 'function') { ReflectOwnKeys = R.ownKeys } else if (Object.getOwnPropertySymbols) { ReflectOwnKeys = function ReflectOwnKeys(target) { return Object.getOwnPropertyNames(target) .concat(Object.getOwnPropertySymbols(target)); }; } else { ReflectOwnKeys = function ReflectOwnKeys(target) { return Object.getOwnPropertyNames(target); }; } function ProcessEmitWarning(warning) { if (console && console.warn) console.warn(warning); } var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) { return value !== value; } function EventEmitter() { EventEmitter.init.call(this); } module.exports = EventEmitter; module.exports.once = once; // Backwards-compat with node 0.10.x EventEmitter.EventEmitter = EventEmitter; EventEmitter.prototype._events = undefined; EventEmitter.prototype._eventsCount = 0; 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. var defaultMaxListeners = 10; function checkListener(listener) { if (typeof listener !== 'function') { throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener); } } Object.defineProperty(EventEmitter, 'defaultMaxListeners', { enumerable: true, get: function() { return defaultMaxListeners; }, set: function(arg) { if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) { throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.'); } defaultMaxListeners = arg; } }); EventEmitter.init = function() { if (this._events === undefined || this._events === Object.getPrototypeOf(this)._events) { this._events = Object.create(null); this._eventsCount = 0; } this._maxListeners = this._maxListeners || undefined; }; // 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 setMaxListeners(n) { if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) { throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.'); } this._maxListeners = n; return this; }; function _getMaxListeners(that) { if (that._maxListeners === undefined) return EventEmitter.defaultMaxListeners; return that._maxListeners; } EventEmitter.prototype.getMaxListeners = function getMaxListeners() { return _getMaxListeners(this); }; EventEmitter.prototype.emit = function emit(type) { var args = []; for (var i = 1; i < arguments.length; i++) args.push(arguments[i]); var doError = (type === 'error'); var events = this._events; if (events !== undefined) doError = (doError && events.error === undefined); else if (!doError) return false; // If there is no 'error' event listener then throw. if (doError) { var er; if (args.length > 0) er = args[0]; if (er instanceof Error) { // Note: The comments on the `throw` lines are intentional, they show // up in Node's output if this results in an unhandled exception. throw er; // Unhandled 'error' event } // At least give some kind of context to the user var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : '')); err.context = er; throw err; // Unhandled 'error' event } var handler = events[type]; if (handler === undefined) return false; if (typeof handler === 'function') { ReflectApply(handler, this, args); } else { var len = handler.length; var listeners = arrayClone(handler, len); for (var i = 0; i < len; ++i) ReflectApply(listeners[i], this, args); } return true; }; function _addListener(target, type, listener, prepend) { var m; var events; var existing; checkListener(listener); events = target._events; if (events === undefined) { events = target._events = Object.create(null); target._eventsCount = 0; } else { // To avoid recursion in the case that type === "newListener"! Before // adding it to the listeners, first emit "newListener". if (events.newListener !== undefined) { target.emit('newListener', type, listener.listener ? listener.listener : listener); // Re-assign `events` because a newListener handler could have caused the // this._events to be assigned to a new object events = target._events; } existing = events[type]; } if (existing === undefined) { // Optimize the case of one listener. Don't need the extra array object. existing = events[type] = listener; ++target._eventsCount; } else { if (typeof existing === 'function') { // Adding the second element, need to change to array. existing = events[type] = prepend ? [listener, existing] : [existing, listener]; // If we've already got an array, just append. } else if (prepend) { existing.unshift(listener); } else { existing.push(listener); } // Check for listener leak m = _getMaxListeners(target); if (m > 0 && existing.length > m && !existing.warned) { existing.warned = true; // No error code for this since it is a Warning // eslint-disable-next-line no-restricted-syntax var w = new Error('Possible EventEmitter memory leak detected. ' + existing.length + ' ' + String(type) + ' listeners ' + 'added. Use emitter.setMaxListeners() to ' + 'increase limit'); w.name = 'MaxListenersExceededWarning'; w.emitter = target; w.type = type; w.count = existing.length; ProcessEmitWarning(w); } } return target; } EventEmitter.prototype.addListener = function addListener(type, listener) { return _addListener(this, type, listener, false); }; EventEmitter.prototype.on = EventEmitter.prototype.addListener; EventEmitter.prototype.prependListener = function prependListener(type, listener) { return _addListener(this, type, listener, true); }; function onceWrapper() { if (!this.fired) { this.target.removeListener(this.type, this.wrapFn); this.fired = true; if (arguments.length === 0) return this.listener.call(this.target); return this.listener.apply(this.target, arguments); } } function _onceWrap(target, type, listener) { var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener }; var wrapped = onceWrapper.bind(state); wrapped.listener = listener; state.wrapFn = wrapped; return wrapped; } EventEmitter.prototype.once = function once(type, listener) { checkListener(listener); this.on(type, _onceWrap(this, type, listener)); return this; }; EventEmitter.prototype.prependOnceListener = function prependOnceListener(type, listener) { checkListener(listener); this.prependListener(type, _onceWrap(this, type, listener)); return this; }; // Emits a 'removeListener' event if and only if the listener was removed. EventEmitter.prototype.removeListener = function removeListener(type, listener) { var list, events, position, i, originalListener; checkListener(listener); events = this._events; if (events === undefined) return this; list = events[type]; if (list === undefined) return this; if (list === listener || list.listener === listener) { if (--this._eventsCount === 0) this._events = Object.create(null); else { delete events[type]; if (events.removeListener) this.emit('removeListener', type, list.listener || listener); } } else if (typeof list !== 'function') { position = -1; for (i = list.length - 1; i >= 0; i--) { if (list[i] === listener || list[i].listener === listener) { originalListener = list[i].listener; position = i; break; } } if (position < 0) return this; if (position === 0) list.shift(); else { spliceOne(list, position); } if (list.length === 1) events[type] = list[0]; if (events.removeListener !== undefined) this.emit('removeListener', type, originalListener || listener); } return this; }; EventEmitter.prototype.off = EventEmitter.prototype.removeListener; EventEmitter.prototype.removeAllListeners = function removeAllListeners(type) { var listeners, events, i; events = this._events; if (events === undefined) return this; // not listening for removeListener, no need to emit if (events.removeListener === undefined) { if (arguments.length === 0) { this._events = Object.create(null); this._eventsCount = 0; } else if (events[type] !== undefined) { if (--this._eventsCount === 0) this._events = Object.create(null); else delete events[type]; } return this; } // emit removeListener for all listeners on all events if (arguments.length === 0) { var keys = Object.keys(events); var key; for (i = 0; i < keys.length; ++i) { key = keys[i]; if (key === 'removeListener') continue; this.removeAllListeners(key); } this.removeAllListeners('removeListener'); this._events = Object.create(null); this._eventsCount = 0; return this; } listeners = events[type]; if (typeof listeners === 'function') { this.removeListener(type, listeners); } else if (listeners !== undefined) { // LIFO order for (i = listeners.length - 1; i >= 0; i--) { this.removeListener(type, listeners[i]); } } return this; }; function _listeners(target, type, unwrap) { var events = target._events; if (events === undefined) return []; var evlistener = events[type]; if (evlistener === undefined) return []; if (typeof evlistener === 'function') return unwrap ? [evlistener.listener || evlistener] : [evlistener]; return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length); } EventEmitter.prototype.listeners = function listeners(type) { return _listeners(this, type, true); }; EventEmitter.prototype.rawListeners = function rawListeners(type) { return _listeners(this, type, false); }; EventEmitter.listenerCount = function(emitter, type) { if (typeof emitter.listenerCount === 'function') { return emitter.listenerCount(type); } else { return listenerCount.call(emitter, type); } }; EventEmitter.prototype.listenerCount = listenerCount; function listenerCount(type) { var events = this._events; if (events !== undefined) { var evlistener = events[type]; if (typeof evlistener === 'function') { return 1; } else if (evlistener !== undefined) { return evlistener.length; } } return 0; } EventEmitter.prototype.eventNames = function eventNames() { return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : []; }; function arrayClone(arr, n) { var copy = new Array(n); for (var i = 0; i < n; ++i) copy[i] = arr[i]; return copy; } function spliceOne(list, index) { for (; index + 1 < list.length; index++) list[index] = list[index + 1]; list.pop(); } function unwrapListeners(arr) { var ret = new Array(arr.length); for (var i = 0; i < ret.length; ++i) { ret[i] = arr[i].listener || arr[i]; } return ret; } function once(emitter, name) { return new Promise(function (resolve, reject) { function errorListener(err) { emitter.removeListener(name, resolver); reject(err); } function resolver() { if (typeof emitter.removeListener === 'function') { emitter.removeListener('error', errorListener); } resolve([].slice.call(arguments)); }; eventTargetAgnosticAddListener(emitter, name, resolver, { once: true }); if (name !== 'error') { addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true }); } }); } function addErrorHandlerIfEventEmitter(emitter, handler, flags) { if (typeof emitter.on === 'function') { eventTargetAgnosticAddListener(emitter, 'error', handler, flags); } } function eventTargetAgnosticAddListener(emitter, name, listener, flags) { if (typeof emitter.on === 'function') { if (flags.once) { emitter.once(name, listener); } else { emitter.on(name, listener); } } else if (typeof emitter.addEventListener === 'function') { // EventTarget does not have `error` event semantics like Node // EventEmitters, we do not listen for `error` events here. emitter.addEventListener(name, function wrapListener(arg) { // IE does not have builtin `{ once: true }` support so we // have to do it manually. if (flags.once) { emitter.removeEventListener(name, wrapListener); } listener(arg); }); } else { throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter); } } },{}],2:[function(require,module,exports){ /* jshint node: true */ 'use strict'; var normalice = require('normalice'); /** # freeice The `freeice` module is a simple way of getting random STUN or TURN server for your WebRTC application. The list of servers (just STUN at this stage) were sourced from this [gist](https://gist.github.com/zziuni/3741933). ## Example Use The following demonstrates how you can use `freeice` with [rtc-quickconnect](https://github.com/rtc-io/rtc-quickconnect): <<< examples/quickconnect.js As the `freeice` module generates ice servers in a list compliant with the WebRTC spec you will be able to use it with raw `RTCPeerConnection` constructors and other WebRTC libraries. ## Hey, don't use my STUN/TURN server! If for some reason your free STUN or TURN server ends up in the list of servers ([stun](https://github.com/DamonOehlman/freeice/blob/master/stun.json) or [turn](https://github.com/DamonOehlman/freeice/blob/master/turn.json)) that is used in this module, you can feel free to open an issue on this repository and those servers will be removed within 24 hours (or sooner). This is the quickest and probably the most polite way to have something removed (and provides us some visibility if someone opens a pull request requesting that a server is added). ## Please add my server! If you have a server that you wish to add to the list, that's awesome! I'm sure I speak on behalf of a whole pile of WebRTC developers who say thanks. To get it into the list, feel free to either open a pull request or if you find that process a bit daunting then just create an issue requesting the addition of the server (make sure you provide all the details, and if you have a Terms of Service then including that in the PR/issue would be awesome). ## I know of a free server, can I add it? Sure, if you do your homework and make sure it is ok to use (I'm currently in the process of reviewing the terms of those STUN servers included from the original list). If it's ok to go, then please see the previous entry for how to add it. ## Current List of Servers * current as at the time of last `README.md` file generation ### STUN <<< stun.json ### TURN <<< turn.json **/ var freeice = function(opts) { // if a list of servers has been provided, then use it instead of defaults var servers = { stun: (opts || {}).stun || require('./stun.json'), turn: (opts || {}).turn || require('./turn.json') }; var stunCount = (opts || {}).stunCount || 2; var turnCount = (opts || {}).turnCount || 0; var selected; function getServers(type, count) { var out = []; var input = [].concat(servers[type]); var idx; while (input.length && out.length < count) { idx = (Math.random() * input.length) | 0; out = out.concat(input.splice(idx, 1)); } return out.map(function(url) { //If it's a not a string, don't try to "normalice" it otherwise using type:url will screw it up if ((typeof url !== 'string') && (! (url instanceof String))) { return url; } else { return normalice(type + ':' + url); } }); } // add stun servers selected = [].concat(getServers('stun', stunCount)); if (turnCount) { selected = selected.concat(getServers('turn', turnCount)); } return selected; }; module.exports = freeice; },{"./stun.json":3,"./turn.json":4,"normalice":8}],3:[function(require,module,exports){ module.exports=[ "stun.l.google.com:19302", "stun1.l.google.com:19302", "stun2.l.google.com:19302", "stun3.l.google.com:19302", "stun4.l.google.com:19302", "stun.ekiga.net", "stun.ideasip.com", "stun.schlund.de", "stun.stunprotocol.org:3478", "stun.voiparound.com", "stun.voipbuster.com", "stun.voipstunt.com", "stun.voxgratia.org" ] },{}],4:[function(require,module,exports){ module.exports=[] },{}],5:[function(require,module,exports){ var WildEmitter = require('wildemitter'); function getMaxVolume (analyser, fftBins) { var maxVolume = -Infinity; analyser.getFloatFrequencyData(fftBins); for(var i=4, ii=fftBins.length; i < ii; i++) { if (fftBins[i] > maxVolume && fftBins[i] < 0) { maxVolume = fftBins[i]; } }; return maxVolume; } var audioContextType; if (typeof window !== 'undefined') { audioContextType = window.AudioContext || window.webkitAudioContext; } // use a single audio context due to hardware limits var audioContext = null; module.exports = function(stream, options) { var harker = new WildEmitter(); // make it not break in non-supported browsers if (!audioContextType) return harker; //Config var options = options || {}, smoothing = (options.smoothing || 0.1), interval = (options.interval || 50), threshold = options.threshold, play = options.play, history = options.history || 10, running = true; // Ensure that just a single AudioContext is internally created audioContext = options.audioContext || audioContext || new audioContextType(); var sourceNode, fftBins, analyser; analyser = audioContext.createAnalyser(); analyser.fftSize = 512; analyser.smoothingTimeConstant = smoothing; fftBins = new Float32Array(analyser.frequencyBinCount); if (stream.jquery) stream = stream[0]; if (stream instanceof HTMLAudioElement || stream instanceof HTMLVideoElement) { //Audio Tag sourceNode = audioContext.createMediaElementSource(stream); if (typeof play === 'undefined') play = true; threshold = threshold || -50; } else { //WebRTC Stream sourceNode = audioContext.createMediaStreamSource(stream); threshold = threshold || -50; } sourceNode.connect(analyser); if (play) analyser.connect(audioContext.destination); harker.speaking = false; harker.suspend = function() { return audioContext.suspend(); } harker.resume = function() { return audioContext.resume(); } Object.defineProperty(harker, 'state', { get: function() { return audioContext.state; }}); audioContext.onstatechange = function() { harker.emit('state_change', audioContext.state); } harker.setThreshold = function(t) { threshold = t; }; harker.setInterval = function(i) { interval = i; }; harker.stop = function() { running = false; harker.emit('volume_change', -100, threshold); if (harker.speaking) { harker.speaking = false; harker.emit('stopped_speaking'); } analyser.disconnect(); sourceNode.disconnect(); }; harker.speakingHistory = []; for (var i = 0; i < history; i++) { harker.speakingHistory.push(0); } // Poll the analyser node to determine if speaking // and emit events if changed var looper = function() { setTimeout(function() { //check if stop has been called if(!running) { return; } var currentVolume = getMaxVolume(analyser, fftBins); harker.emit('volume_change', currentVolume, threshold); var history = 0; if (currentVolume > threshold && !harker.speaking) { // trigger quickly, short history for (var i = harker.speakingHistory.length - 3; i < harker.speakingHistory.length; i++) { history += harker.speakingHistory[i]; } if (history >= 2) { harker.speaking = true; harker.emit('speaking'); } } else if (currentVolume < threshold && harker.speaking) { for (var i = 0; i < harker.speakingHistory.length; i++) { history += harker.speakingHistory[i]; } if (history == 0) { harker.speaking = false; harker.emit('stopped_speaking'); } } harker.speakingHistory.shift(); harker.speakingHistory.push(0 + (currentVolume > threshold)); looper(); }, interval); }; looper(); return harker; } },{"wildemitter":25}],6:[function(require,module,exports){ if (typeof Object.create === 'function') { // implementation from standard node.js 'util' module module.exports = function inherits(ctor, superCtor) { if (superCtor) { ctor.super_ = superCtor ctor.prototype = Object.create(superCtor.prototype, { constructor: { value: ctor, enumerable: false, writable: true, configurable: true } }) } }; } else { // old school shim for old browsers module.exports = function inherits(ctor, superCtor) { if (superCtor) { ctor.super_ = superCtor var TempCtor = function () {} TempCtor.prototype = superCtor.prototype ctor.prototype = new TempCtor() ctor.prototype.constructor = ctor } } } },{}],7:[function(require,module,exports){ /* * JSNLog 2.30.0 * Open source under the MIT License. * Copyright 2012-2017 Mattijs Perdeck All rights reserved. */ var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); function JL(loggerName) { // If name is empty, return the root logger if (!loggerName) { return JL.__; } // Implements Array.reduce. JSNLog supports IE8+ and reduce is not supported in that browser. // Same interface as the standard reduce, except that if (!Array.prototype.reduce) { Array.prototype.reduce = function (callback, initialValue) { var previousValue = initialValue; for (var i = 0; i < this.length; i++) { previousValue = callback(previousValue, this[i], i, this); } return previousValue; }; } var accumulatedLoggerName = ''; var logger = ('.' + loggerName).split('.').reduce(function (prev, curr, idx, arr) { // if loggername is a.b.c, than currentLogger will be set to the loggers // root (prev: JL, curr: '') // a (prev: JL.__, curr: 'a') // a.b (prev: JL.__.__a, curr: 'b') // a.b.c (prev: JL.__.__a.__a.b, curr: 'c') // Note that when a new logger name is encountered (such as 'a.b.c'), // a new logger object is created and added as a property to the parent ('a.b'). // The root logger is added as a property of the JL object itself. // It is essential that the name of the property containing the child logger // contains the full 'path' name of the child logger ('a.b.c') instead of // just the bit after the last period ('c'). // This is because the parent inherits properties from its ancestors. // So if the root has a child logger 'c' (stored in a property 'c' of the root logger), // then logger 'a.b' has that same property 'c' through inheritance. // The names of the logger properties start with __, so the root logger // (which has name ''), has a nice property name '__'. // accumulatedLoggerName evaluates false ('' is falsy) in first iteration when prev is the root logger. // accumulatedLoggerName will be the logger name corresponding with the logger in currentLogger. // Keep in mind that the currentLogger may not be defined yet, so can't get the name from // the currentLogger object itself. if (accumulatedLoggerName) { accumulatedLoggerName += '.' + curr; } else { accumulatedLoggerName = curr; } var currentLogger = prev['__' + accumulatedLoggerName]; // If the currentLogger (or the actual logger being sought) does not yet exist, // create it now. if (currentLogger === undefined) { // Set the prototype of the Logger constructor function to the parent of the logger // to be created. This way, __proto of the new logger object will point at the parent. // When logger.level is evaluated and is not present, the JavaScript runtime will // walk down the prototype chain to find the first ancestor with a level property. // // Note that prev at this point refers to the parent logger. JL.Logger.prototype = prev; currentLogger = new JL.Logger(accumulatedLoggerName); prev['__' + accumulatedLoggerName] = currentLogger; } return currentLogger; }, JL.__); return logger; } (function (JL) { // Initialise requestId to empty string. If you don't do this and the user // does not set it via setOptions, then the JSNLog-RequestId header will // have value "undefined", which doesn't look good in a log. // // Note that you always want to send a requestId as part of log requests, // otherwise the server side component doesn't know this is a log request // and may create a new request id for the log request, causing confusion // in the log. JL.requestId = ''; // Number uniquely identifying every log entry within the request. JL.entryId = 0; // Allow property injection of these classes, to enable unit testing JL._createXMLHttpRequest = function () { return new XMLHttpRequest(); }; JL._getTime = function () { return (new Date).getTime(); }; JL._console = console; // ----- private variables JL._appenderNames = []; /** Copies the value of a property from one object to the other. This is used to copy property values as part of setOption for loggers and appenders. Because loggers inherit property values from their parents, it is important never to create a property on a logger if the intent is to inherit from the parent. Copying rules: 1) if the from property is undefined (for example, not mentioned in a JSON object), the to property is not affected at all. 2) if the from property is null, the to property is deleted (so the logger will inherit from its parent). 3) Otherwise, the from property is copied to the to property. */ function copyProperty(propertyName, from, to) { if (from[propertyName] === undefined) { return; } if (from[propertyName] === null) { delete to[propertyName]; return; } to[propertyName] = from[propertyName]; } /** Returns true if a log should go ahead. Does not check level. @param filters Filters that determine whether a log can go ahead. */ function allow(filters) { // If enabled is not null or undefined, then if it is false, then return false // Note that undefined==null (!) if (!(JL.enabled == null)) { if (!JL.enabled) { return false; } } // If the regex contains a bug, that will throw an exception. // Ignore this, and pass the log item (better too much than too little). try { if (filters.userAgentRegex) { if (!new RegExp(filters.userAgentRegex).test(navigator.userAgent)) { return false; } } } catch (e) { } try { if (filters.ipRegex && JL.clientIP) { if (!new RegExp(filters.ipRegex).test(JL.clientIP)) { return false; } } } catch (e) { } return true; } /** Returns true if a log should go ahead, based on the message. @param filters Filters that determine whether a log can go ahead. @param message Message to be logged. */ function allowMessage(filters, message) { // If the regex contains a bug, that will throw an exception. // Ignore this, and pass the log item (better too much than too little). try { if (filters.disallow) { if (new RegExp(filters.disallow).test(message)) { return false; } } } catch (e) { } return true; } // If logObject is a function, the function is evaluated (without parameters) // and the result returned. // Otherwise, logObject itself is returned. function stringifyLogObjectFunction(logObject) { if (typeof logObject == "function") { if (logObject instanceof RegExp) { return logObject.toString(); } else { return logObject(); } } return logObject; } var StringifiedLogObject = /** @class */ (function () { // * msg - // if the logObject is a scalar (after possible function evaluation), this is set to // string representing the scalar. Otherwise it is left undefined. // * meta - // if the logObject is an object (after possible function evaluation), this is set to // that object. Otherwise it is left undefined. // * finalString - // This is set to the string representation of logObject (after possible function evaluation), // regardless of whether it is an scalar or an object. An object is stringified to a JSON string. // Note that you can't call this field "final", because as some point this was a reserved // JavaScript keyword and using final trips up some minifiers. function StringifiedLogObject(msg, meta, finalString) { this.msg = msg; this.meta = meta; this.finalString = finalString; } return StringifiedLogObject; }()); // Takes a logObject, which can be // * a scalar // * an object // * a parameterless function, which returns the scalar or object to log. // Returns a stringifiedLogObject function stringifyLogObject(logObject) { // Note that this works if logObject is null. // typeof null is object. // JSON.stringify(null) returns "null". var actualLogObject = stringifyLogObjectFunction(logObject); var finalString; // Note that typeof actualLogObject should not be "function", because that has // been resolved with stringifyLogObjectFunction. switch (typeof actualLogObject) { case "string": return new StringifiedLogObject(actualLogObject, null, actualLogObject); case "number": finalString = actualLogObject.toString(); return new StringifiedLogObject(finalString, null, finalString); case "boolean": finalString = actualLogObject.toString(); return new StringifiedLogObject(finalString, null, finalString); case "undefined": return new StringifiedLogObject("undefined", null, "undefined"); case "object": if ((actualLogObject instanceof RegExp) || (actualLogObject instanceof String) || (actualLogObject instanceof Number) || (actualLogObject instanceof Boolean)) { finalString = actualLogObject.toString(); return new StringifiedLogObject(finalString, null, finalString); } else { if (typeof JL.serialize === 'function') { finalString = JL.serialize.call(this, actualLogObject); } else { finalString = JSON.stringify(actualLogObject); } // Set the msg field to "" instead of null. Some Winston transports // assume that the msg field is not null. return new StringifiedLogObject("", actualLogObject, finalString); } default: return new StringifiedLogObject("unknown", null, "unknown"); } } function setOptions(options) { copyProperty("enabled", options, this); copyProperty("maxMessages", options, this); copyProperty("defaultAjaxUrl", options, this); copyProperty("clientIP", options, this); copyProperty("requestId", options, this); copyProperty("defaultBeforeSend", options, this); copyProperty("serialize", options, this); return this; } JL.setOptions = setOptions; function getAllLevel() { return -2147483648; } JL.getAllLevel = getAllLevel; function getTraceLevel() { return 1000; } JL.getTraceLevel = getTraceLevel; function getDebugLevel() { return 2000; } JL.getDebugLevel = getDebugLevel; function getInfoLevel() { return 3000; } JL.getInfoLevel = getInfoLevel; function getWarnLevel() { return 4000; } JL.getWarnLevel = getWarnLevel; function getErrorLevel() { return 5000; } JL.getErrorLevel = getErrorLevel; function getFatalLevel() { return 6000; } JL.getFatalLevel = getFatalLevel; function getOffLevel() { return 2147483647; } JL.getOffLevel = getOffLevel; function levelToString(level) { if (level <= 1000) { return "trace"; } if (level <= 2000) { return "debug"; } if (level <= 3000) { return "info"; } if (level <= 4000) { return "warn"; } if (level <= 5000) { return "error"; } return "fatal"; } // --------------------- var Exception = /** @class */ (function () { // data replaces message. It takes not just strings, but also objects and functions, just like the log function. // internally, the string representation is stored in the message property (inherited from Error) // // inner: inner exception. Can be null or undefined. function Exception(data, inner) { this.inner = inner; this.name = "JL.Exception"; this.message = stringifyLogObject(data).finalString; } return Exception; }()); JL.Exception = Exception; // Derive Exception from Error (a Host object), so browsers // are more likely to produce a stack trace for it in their console. // // Note that instanceof against an object created with this constructor // will return true in these cases: // <object> instanceof JL.Exception); // <object> instanceof Error); Exception.prototype = new Error(); // --------------------- var LogItem = /** @class */ (function () { // l: level // m: message // n: logger name // t (timeStamp) is number of milliseconds since 1 January 1970 00:00:00 UTC // u: number uniquely identifying this entry for this request. // // Keeping the property names really short, because they will be sent in the // JSON payload to the server. function LogItem(l, m, n, t, u) { this.l = l; this.m = m; this.n = n; this.t = t; this.u = u; } return LogItem; }()); JL.LogItem = LogItem; function newLogItem(levelNbr, message, loggerName) { JL.entryId++; return new LogItem(levelNbr, message, loggerName, JL._getTime(), JL.entryId); } function clearTimer(timer) { if (timer.id) { clearTimeout(timer.id); timer.id = null; } } function setTimer(timer, timeoutMs, callback) { var that = this; if (!timer.id) { timer.id = setTimeout(function () { // use call to ensure that the this as used inside sendBatch when it runs is the // same this at this point. callback.call(that); }, timeoutMs); } } var Appender = /** @class */ (function () { // sendLogItems takes an array of log items. It will be called when // the appender has items to process (such as, send to the server). // sendLogItems will call successCallback after the items have been successfully sent. // // Note that after sendLogItems returns, the appender may truncate // the LogItem array, so the function has to copy the content of the array // in some fashion (eg. serialize) before returning. function Appender(appenderName, sendLogItems) { this.appenderName = appenderName; this.sendLogItems = sendLogItems; this.level = JL.getTraceLevel(); // set to super high level, so if user increases level, level is unlikely to get // above sendWithBufferLevel this.sendWithBufferLevel = 2147483647; this.storeInBufferLevel = -2147483648; this.bufferSize = 0; // buffering switch off by default this.batchSize = 1; this.maxBatchSize = 20; this.batchTimeout = 2147483647; this.sendTimeout = 5000; // Holds all log items with levels higher than storeInBufferLevel // but lower than level. These items may never be sent. this.buffer = []; // Holds all items that we do want to send, until we have a full // batch (as determined by batchSize). this.batchBuffer = []; // Holds the id of the timer implementing the batch timeout. // Can be null. // This is an object, so it can be passed to a method that updated the timer variable. this.batchTimeoutTimer = { id: null }; // Holds the id of the timer implementing the send timeout. // Can be null. this.sendTimeoutTimer = { id: null }; // Number of log items that has been skipped due to batch buffer at max size, // since appender creation or since creation of the last "skipped" warning log entry. this.nbrLogItemsSkipped = 0; // Will be 0 if no log request is outstanding at the moment. // Otherwise the number of log items in the outstanding request. this.nbrLogItemsBeingSent = 0; var emptyNameErrorMessage = "Trying to create an appender without a name or with an empty name"; // This evaluates to true if appenderName is either null or undefined! // Do not check here if the name is "", because that would stop you creating the // default appender. if (appenderName == undefined) { throw emptyNameErrorMessage; } if (JL._appenderNames.indexOf(appenderName) != -1) { // If user passed in "", that will now have been picked up as a duplicate // because default appender also uses "". if (!appenderName) { throw emptyNameErrorMessage; } throw "Multiple appenders use the same name " + appenderName; } JL._appenderNames.push(appenderName); } Appender.prototype.addLogItemsToBuffer = function (logItems) { // If the batch buffer has reached its maximum limit, // skip the log item and increase the "skipped items" counter. if (this.batchBuffer.length >= this.maxBatchSize) { this.nbrLogItemsSkipped += logItems.length; return; } // If maxMessages is not null or undefined, then decrease it by the batch size. // This can result in a negative maxMessages. // Note that undefined==null (!) // // Note that we may be sending more messages than the maxMessages limit allows, // if we stored trace messages. Rationale is the buffer for trace messages is limited, // and if we cut off at exactly maxMessages, we'd also loose the high severity message // that caused the trace messages to be sent (unless we cater for this specifically, which // is more complexity). // // If there are multiple appenders sending the same message, maxMessage will be decreased // by each appender for the same message. This is: // 1) only appenders know whether a message will actually be sent (based on storeInBufferLevel), // so the loggers couldn't do this update; // 2) if you have multiple appenders hitting the same server, this may be what you want. // // In most cases there is only 1 appender, so this then doesn't matter. if (!(JL.maxMessages == null)) { if (JL.maxMessages < 1) { return; } JL.maxMessages -= logItems.length; } this.batchBuffer = this.batchBuffer.concat(logItems); // If this is the first item in the buffer, set the timer // to ensure it will be sent within the timeout period. // If it is not the first item, leave the timer alone so to not to // increase the timeout for the first item. // // To determine if this is the first item, look at the timer variable. // Do not look at the buffer length, because we also put items in the buffer // via a concat (bypassing this function). // // The setTimer method only sets the timer if it is not already running. var that = this; setTimer(this.batchTimeoutTimer, this.batchTimeout, function () { that.sendBatch.call(that); }); }; ; Appender.prototype.batchBufferHasOverdueMessages = function () { for (var i = 0; i < this.batchBuffer.length; i++) { var messageAgeMs = JL._getTime() - this.batchBuffer[i].t; if (messageAgeMs > this.batchTimeout) { return true; } } return false; }; // Returns true if no more message will ever be added to the batch buffer, // but the batch buffer has messages now - so if there are not enough to make up a batch, // and there is no batch timeout, then they will never be sent. This is especially important if // maxMessages was reached while jsnlog.js was retrying sending messages to the server. Appender.prototype.batchBufferHasStrandedMessage = function () { return (!(JL.maxMessages == null)) && (JL.maxMessages < 1) && (this.batchBuffer.length > 0); }; Appender.prototype.sendBatchIfComplete = function () { if ((this.batchBuffer.length >= this.batchSize) || this.batchBufferHasOverdueMessages() || this.batchBufferHasStrandedMessage()) { this.sendBatch(); } }; Appender.prototype.onSendingEnded = function () { clearTimer(this.sendTimeoutTimer); this.nbrLogItemsBeingSent = 0; this.sendBatchIfComplete(); }; Appender.prototype.setOptions = function (options) { copyProperty("level", options, this); copyProperty("ipRegex", options, this); copyProperty("userAgentRegex", options, this); copyProperty("disallow", options, this); copyProperty("sendWithBufferLevel", options, this); copyProperty("storeInBufferLevel", options, this); copyProperty("bufferSize", options, this); copyProperty("batchSize", options, this); copyProperty("maxBatchSize", options, this); copyProperty("batchTimeout", options, this); copyProperty("sendTimeout", options, this); if (this.bufferSize < this.buffer.length) { this.buffer.length = this.bufferSize; } if (this.maxBatchSize < this.batchSize) { throw new JL.Exception({ "message": "maxBatchSize cannot be smaller than batchSize", "maxBatchSize": this.maxBatchSize, "batchSize": this.batchSize }); } return this; }; /** Called by a logger to log a log item. If in response to this call one or more log items need to be processed (eg., sent to the server), this method calls this.sendLogItems with an array with all items to be processed. Note that the name and parameters of this function must match those of the log function of a Winston transport object, so that users can use these transports as appenders. That is why there are many parameters that are not actually used by this function. level - string with the level ("t