nextgen-events
Version:
The next generation of events handling for javascript! New: abstract away the network!
1,743 lines (1,259 loc) • 215 kB
JavaScript
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
(function (global){
/*
Next Gen Events
Copyright (c) 2015 - 2016 Cédric Ronvel
The MIT License (MIT)
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" ;
function NextGenEvents() { return Object.create( NextGenEvents.prototype ) ; }
module.exports = NextGenEvents ;
NextGenEvents.prototype.__prototypeUID__ = 'nextgen-events/NextGenEvents' ;
NextGenEvents.prototype.__prototypeVersion__ = require( '../package.json' ).version ;
/* Basic features, more or less compatible with Node.js */
NextGenEvents.SYNC = -Infinity ;
// Not part of the prototype, because it should not pollute userland's prototype.
// It has an eventEmitter as 'this' anyway (always called using call()).
NextGenEvents.init = function init()
{
Object.defineProperty( this , '__ngev' , {
configurable: true ,
value: {
nice: NextGenEvents.SYNC ,
interruptible: false ,
recursion: 0 ,
contexts: {} ,
// States by events
states: {} ,
// State groups by events
stateGroups: {} ,
// Listeners by events
listeners: {
// Special events
error: [] ,
interrupt: [] ,
newListener: [] ,
removeListener: []
}
}
} ) ;
} ;
// Use it with .bind()
NextGenEvents.filterOutCallback = function( what , currentElement ) { return what !== currentElement ; } ;
// .addListener( eventName , [fn] , [options] )
NextGenEvents.prototype.addListener = function addListener( eventName , fn , options )
{
var listener = {} , newListenerListeners ;
if ( ! this.__ngev ) { NextGenEvents.init.call( this ) ; }
if ( ! this.__ngev.listeners[ eventName ] ) { this.__ngev.listeners[ eventName ] = [] ; }
if ( ! eventName || typeof eventName !== 'string' ) { throw new TypeError( ".addListener(): argument #0 should be a non-empty string" ) ; }
if ( typeof fn !== 'function' ) { options = fn ; fn = undefined ; }
if ( ! options || typeof options !== 'object' ) { options = {} ; }
listener.fn = fn || options.fn ;
listener.id = options.id !== undefined ? options.id : listener.fn ;
listener.once = !! options.once ;
listener.async = !! options.async ;
listener.eventObject = !! options.eventObject ;
listener.nice = options.nice !== undefined ? Math.floor( options.nice ) : NextGenEvents.SYNC ;
listener.context = typeof options.context === 'string' ? options.context : null ;
if ( typeof listener.fn !== 'function' )
{
throw new TypeError( ".addListener(): a function or an object with a 'fn' property which value is a function should be provided" ) ;
}
// Implicit context creation
if ( listener.context && typeof listener.context === 'string' && ! this.__ngev.contexts[ listener.context ] )
{
this.addListenerContext( listener.context ) ;
}
// Note: 'newListener' and 'removeListener' event return an array of listener, but not the event name.
// So the event's name can be retrieved in the listener itself.
listener.event = eventName ;
if ( this.__ngev.listeners.newListener.length )
{
// Extra care should be taken with the 'newListener' event, we should avoid recursion
// in the case that eventName === 'newListener', but inside a 'newListener' listener,
// .listenerCount() should report correctly
newListenerListeners = this.__ngev.listeners.newListener.slice() ;
this.__ngev.listeners[ eventName ].push( listener ) ;
// Return an array, because one day, .addListener() may support multiple event addition at once,
// e.g.: .addListener( { request: onRequest, close: onClose, error: onError } ) ;
NextGenEvents.emitEvent( {
emitter: this ,
name: 'newListener' ,
args: [ [ listener ] ] ,
listeners: newListenerListeners
} ) ;
if ( this.__ngev.states[ eventName ] ) { NextGenEvents.emitToOneListener( this.__ngev.states[ eventName ] , listener ) ; }
return this ;
}
this.__ngev.listeners[ eventName ].push( listener ) ;
if ( this.__ngev.states[ eventName ] ) { NextGenEvents.emitToOneListener( this.__ngev.states[ eventName ] , listener ) ; }
return this ;
} ;
NextGenEvents.prototype.on = NextGenEvents.prototype.addListener ;
// Shortcut
// .once( eventName , [fn] , [options] )
NextGenEvents.prototype.once = function once( eventName , fn , options )
{
if ( fn && typeof fn === 'object' ) { fn.once = true ; }
else if ( options && typeof options === 'object' ) { options.once = true ; }
else { options = { once: true } ; }
return this.addListener( eventName , fn , options ) ;
} ;
NextGenEvents.prototype.removeListener = function removeListener( eventName , id )
{
var i , length , newListeners = [] , removedListeners = [] ;
if ( ! eventName || typeof eventName !== 'string' ) { throw new TypeError( ".removeListener(): argument #0 should be a non-empty string" ) ; }
if ( ! this.__ngev ) { NextGenEvents.init.call( this ) ; }
if ( ! this.__ngev.listeners[ eventName ] ) { this.__ngev.listeners[ eventName ] = [] ; }
length = this.__ngev.listeners[ eventName ].length ;
// It's probably faster to create a new array of listeners
for ( i = 0 ; i < length ; i ++ )
{
if ( this.__ngev.listeners[ eventName ][ i ].id === id )
{
removedListeners.push( this.__ngev.listeners[ eventName ][ i ] ) ;
}
else
{
newListeners.push( this.__ngev.listeners[ eventName ][ i ] ) ;
}
}
this.__ngev.listeners[ eventName ] = newListeners ;
if ( removedListeners.length && this.__ngev.listeners.removeListener.length )
{
this.emit( 'removeListener' , removedListeners ) ;
}
return this ;
} ;
NextGenEvents.prototype.off = NextGenEvents.prototype.removeListener ;
NextGenEvents.prototype.removeAllListeners = function removeAllListeners( eventName )
{
var removedListeners ;
if ( ! this.__ngev ) { NextGenEvents.init.call( this ) ; }
if ( eventName )
{
// Remove all listeners for a particular event
if ( ! eventName || typeof eventName !== 'string' ) { throw new TypeError( ".removeAllListeners(): argument #0 should be undefined or a non-empty string" ) ; }
if ( ! this.__ngev.listeners[ eventName ] ) { this.__ngev.listeners[ eventName ] = [] ; }
removedListeners = this.__ngev.listeners[ eventName ] ;
this.__ngev.listeners[ eventName ] = [] ;
if ( removedListeners.length && this.__ngev.listeners.removeListener.length )
{
this.emit( 'removeListener' , removedListeners ) ;
}
}
else
{
// Remove all listeners for any events
// 'removeListener' listeners cannot be triggered: they are already deleted
this.__ngev.listeners = {} ;
}
return this ;
} ;
NextGenEvents.listenerWrapper = function listenerWrapper( listener , event , context )
{
var returnValue , serial , listenerCallback ;
if ( event.interrupt ) { return ; }
if ( listener.async )
{
//serial = context && context.serial ;
if ( context )
{
serial = context.serial ;
context.ready = ! serial ;
}
listenerCallback = function( arg ) {
event.listenersDone ++ ;
// Async interrupt
if ( arg && event.emitter.__ngev.interruptible && ! event.interrupt && event.name !== 'interrupt' )
{
event.interrupt = arg ;
if ( event.callback )
{
event.callback( event.interrupt , event ) ;
delete event.callback ;
}
event.emitter.emit( 'interrupt' , event.interrupt ) ;
}
else if ( event.listenersDone >= event.listeners.length && event.callback )
{
event.callback( undefined , event ) ;
delete event.callback ;
}
// Process the queue if serialized
if ( serial ) { NextGenEvents.processQueue.call( event.emitter , listener.context , true ) ; }
} ;
if ( listener.eventObject ) { listener.fn( event , listenerCallback ) ; }
else { returnValue = listener.fn.apply( undefined , event.args.concat( listenerCallback ) ) ; }
}
else
{
if ( listener.eventObject ) { listener.fn( event ) ; }
else { returnValue = listener.fn.apply( undefined , event.args ) ; }
event.listenersDone ++ ;
}
// Interrupt if non-falsy return value, if the emitter is interruptible, not already interrupted (emit once),
// and not within an 'interrupt' event.
if ( returnValue && event.emitter.__ngev.interruptible && ! event.interrupt && event.name !== 'interrupt' )
{
event.interrupt = returnValue ;
if ( event.callback )
{
event.callback( event.interrupt , event ) ;
delete event.callback ;
}
event.emitter.emit( 'interrupt' , event.interrupt ) ;
}
else if ( event.listenersDone >= event.listeners.length && event.callback )
{
event.callback( undefined , event ) ;
delete event.callback ;
}
} ;
// A unique event ID
var nextEventId = 0 ;
/*
emit( [nice] , eventName , [arg1] , [arg2] , [...] , [emitCallback] )
*/
NextGenEvents.prototype.emit = function emit()
{
var event ;
event = { emitter: this } ;
// Arguments handling
if ( typeof arguments[ 0 ] === 'number' )
{
event.nice = Math.floor( arguments[ 0 ] ) ;
event.name = arguments[ 1 ] ;
if ( ! event.name || typeof event.name !== 'string' ) { throw new TypeError( ".emit(): when argument #0 is a number, argument #1 should be a non-empty string" ) ; }
if ( typeof arguments[ arguments.length - 1 ] === 'function' )
{
event.callback = arguments[ arguments.length - 1 ] ;
event.args = Array.prototype.slice.call( arguments , 2 , -1 ) ;
}
else
{
event.args = Array.prototype.slice.call( arguments , 2 ) ;
}
}
else
{
//event.nice = this.__ngev.nice ;
event.name = arguments[ 0 ] ;
if ( ! event.name || typeof event.name !== 'string' ) { throw new TypeError( ".emit(): argument #0 should be an number or a non-empty string" ) ; }
event.args = Array.prototype.slice.call( arguments , 1 ) ;
if ( typeof arguments[ arguments.length - 1 ] === 'function' )
{
event.callback = arguments[ arguments.length - 1 ] ;
event.args = Array.prototype.slice.call( arguments , 1 , -1 ) ;
}
else
{
event.args = Array.prototype.slice.call( arguments , 1 ) ;
}
}
return NextGenEvents.emitEvent( event ) ;
} ;
/*
At this stage, 'event' should be an object having those properties:
* emitter: the event emitter
* name: the event name
* args: array, the arguments of the event
* nice: (optional) nice value
* callback: (optional) a callback for emit
* listeners: (optional) override the listeners array stored in __ngev
*/
NextGenEvents.emitEvent = function emitEvent( event )
{
var self = event.emitter ,
i , iMax , count = 0 , state , removedListeners ;
if ( ! self.__ngev ) { NextGenEvents.init.call( self ) ; }
state = self.__ngev.states[ event.name ] ;
// This is a state event, register it now!
if ( state !== undefined )
{
if ( state && event.args.length === state.args.length &&
event.args.every( function( arg , index ) { return arg === state.args[ index ] ; } ) )
{
// The emitter is already in this exact state, skip it now!
return ;
}
// Unset all states of that group
self.__ngev.stateGroups[ event.name ].forEach( function( eventName ) {
self.__ngev.states[ eventName ] = null ;
} ) ;
self.__ngev.states[ event.name ] = event ;
}
if ( ! self.__ngev.listeners[ event.name ] ) { self.__ngev.listeners[ event.name ] = [] ; }
event.id = nextEventId ++ ;
event.listenersDone = 0 ;
event.once = !! event.once ;
if ( event.nice === undefined || event.nice === null ) { event.nice = self.__ngev.nice ; }
// Trouble arise when a listener is removed from another listener, while we are still in the loop.
// So we have to COPY the listener array right now!
if ( ! event.listeners ) { event.listeners = self.__ngev.listeners[ event.name ].slice() ; }
// Increment self.__ngev.recursion
self.__ngev.recursion ++ ;
removedListeners = [] ;
// Emit the event to all listeners!
for ( i = 0 , iMax = event.listeners.length ; i < iMax ; i ++ )
{
count ++ ;
NextGenEvents.emitToOneListener( event , event.listeners[ i ] , removedListeners ) ;
}
// Decrement recursion
self.__ngev.recursion -- ;
// Emit 'removeListener' after calling listeners
if ( removedListeners.length && self.__ngev.listeners.removeListener.length )
{
self.emit( 'removeListener' , removedListeners ) ;
}
// 'error' event is a special case: it should be listened for, or it will throw an error
if ( ! count )
{
if ( event.name === 'error' )
{
if ( event.args[ 0 ] ) { throw event.args[ 0 ] ; }
else { throw Error( "Uncaught, unspecified 'error' event." ) ; }
}
if ( event.callback )
{
event.callback( undefined , event ) ;
delete event.callback ;
}
}
return event ;
} ;
// If removedListeners is not given, then one-time listener emit the 'removeListener' event,
// if given: that's the caller business to do it
NextGenEvents.emitToOneListener = function emitToOneListener( event , listener , removedListeners )
{
var self = event.emitter ,
context , currentNice , emitRemoveListener = false ;
context = listener.context && self.__ngev.contexts[ listener.context ] ;
// If the listener context is disabled...
if ( context && context.status === NextGenEvents.CONTEXT_DISABLED ) { return ; }
// The nice value for this listener...
if ( context ) { currentNice = Math.max( event.nice , listener.nice , context.nice ) ; }
else { currentNice = Math.max( event.nice , listener.nice ) ; }
if ( listener.once )
{
// We should remove the current listener RIGHT NOW because of recursive .emit() issues:
// one listener may eventually fire this very same event synchronously during the current loop.
self.__ngev.listeners[ event.name ] = self.__ngev.listeners[ event.name ].filter(
NextGenEvents.filterOutCallback.bind( undefined , listener )
) ;
if ( removedListeners ) { removedListeners.push( listener ) ; }
else { emitRemoveListener = true ; }
}
if ( context && ( context.status === NextGenEvents.CONTEXT_QUEUED || ! context.ready ) )
{
// Almost all works should be done by .emit(), and little few should be done by .processQueue()
context.queue.push( { event: event , listener: listener , nice: currentNice } ) ;
}
else
{
try {
if ( currentNice < 0 )
{
if ( self.__ngev.recursion >= - currentNice )
{
setImmediate( NextGenEvents.listenerWrapper.bind( self , listener , event , context ) ) ;
}
else
{
NextGenEvents.listenerWrapper.call( self , listener , event , context ) ;
}
}
else
{
setTimeout( NextGenEvents.listenerWrapper.bind( self , listener , event , context ) , currentNice ) ;
}
}
catch ( error ) {
// Catch error, just to decrement self.__ngev.recursion, re-throw after that...
self.__ngev.recursion -- ;
throw error ;
}
}
// Emit 'removeListener' after calling the listener
if ( emitRemoveListener && self.__ngev.listeners.removeListener.length )
{
self.emit( 'removeListener' , [ listener ] ) ;
}
} ;
NextGenEvents.prototype.listeners = function listeners( eventName )
{
if ( ! eventName || typeof eventName !== 'string' ) { throw new TypeError( ".listeners(): argument #0 should be a non-empty string" ) ; }
if ( ! this.__ngev ) { NextGenEvents.init.call( this ) ; }
if ( ! this.__ngev.listeners[ eventName ] ) { this.__ngev.listeners[ eventName ] = [] ; }
// Do not return the array, shallow copy it
return this.__ngev.listeners[ eventName ].slice() ;
} ;
NextGenEvents.listenerCount = function( emitter , eventName )
{
if ( ! emitter || ! ( emitter instanceof NextGenEvents ) ) { throw new TypeError( ".listenerCount(): argument #0 should be an instance of NextGenEvents" ) ; }
return emitter.listenerCount( eventName ) ;
} ;
NextGenEvents.prototype.listenerCount = function( eventName )
{
if ( ! eventName || typeof eventName !== 'string' ) { throw new TypeError( ".listenerCount(): argument #1 should be a non-empty string" ) ; }
if ( ! this.__ngev ) { NextGenEvents.init.call( this ) ; }
if ( ! this.__ngev.listeners[ eventName ] ) { this.__ngev.listeners[ eventName ] = [] ; }
return this.__ngev.listeners[ eventName ].length ;
} ;
NextGenEvents.prototype.setNice = function setNice( nice )
{
if ( ! this.__ngev ) { NextGenEvents.init.call( this ) ; }
//if ( typeof nice !== 'number' ) { throw new TypeError( ".setNice(): argument #0 should be a number" ) ; }
this.__ngev.nice = Math.floor( +nice || 0 ) ;
} ;
NextGenEvents.prototype.setInterruptible = function setInterruptible( value )
{
if ( ! this.__ngev ) { NextGenEvents.init.call( this ) ; }
//if ( typeof nice !== 'number' ) { throw new TypeError( ".setNice(): argument #0 should be a number" ) ; }
this.__ngev.interruptible = !! value ;
} ;
// Make two objects sharing the same event bus
NextGenEvents.share = function( source , target )
{
if ( ! ( source instanceof NextGenEvents ) || ! ( target instanceof NextGenEvents ) )
{
throw new TypeError( 'NextGenEvents.share() arguments should be instances of NextGenEvents' ) ;
}
if ( ! source.__ngev ) { NextGenEvents.init.call( source ) ; }
Object.defineProperty( target , '__ngev' , {
configurable: true ,
value: source.__ngev
} ) ;
} ;
NextGenEvents.reset = function reset( emitter )
{
Object.defineProperty( emitter , '__ngev' , {
configurable: true ,
value: null
} ) ;
} ;
// There is no such thing in NextGenEvents, however, we need to be compatible with node.js events at best
NextGenEvents.prototype.setMaxListeners = function() {} ;
// Sometime useful as a no-op callback...
NextGenEvents.noop = function() {} ;
/* Next Gen feature: states! */
// .defineStates( exclusiveState1 , [exclusiveState2] , [exclusiveState3] , ... )
NextGenEvents.prototype.defineStates = function defineStates()
{
var self = this ,
states = Array.prototype.slice.call( arguments ) ;
if ( ! this.__ngev ) { NextGenEvents.init.call( this ) ; }
states.forEach( function( state ) {
self.__ngev.states[ state ] = null ;
self.__ngev.stateGroups[ state ] = states ;
} ) ;
} ;
NextGenEvents.prototype.hasState = function hasState( state )
{
if ( ! this.__ngev ) { NextGenEvents.init.call( this ) ; }
return !! this.__ngev.states[ state ] ;
} ;
NextGenEvents.prototype.getAllStates = function getAllStates()
{
var self = this ;
if ( ! this.__ngev ) { NextGenEvents.init.call( this ) ; }
return Object.keys( this.__ngev.states ).filter( function( e ) { return self.__ngev.states[ e ] ; } ) ;
} ;
/* Next Gen feature: groups! */
NextGenEvents.groupAddListener = function groupAddListener( emitters , eventName , fn , options )
{
// Manage arguments
if ( typeof fn !== 'function' ) { options = fn ; fn = undefined ; }
if ( ! options || typeof options !== 'object' ) { options = {} ; }
fn = fn || options.fn ;
delete options.fn ;
// Preserve the listener ID, so groupRemoveListener() will work as expected
options.id = options.id || fn ;
emitters.forEach( function( emitter ) {
emitter.addListener( eventName , fn.bind( undefined , emitter ) , options ) ;
} ) ;
} ;
NextGenEvents.groupOn = NextGenEvents.groupAddListener ;
// Once per emitter
NextGenEvents.groupOnce = function groupOnce( emitters , eventName , fn , options )
{
if ( fn && typeof fn === 'object' ) { fn.once = true ; }
else if ( options && typeof options === 'object' ) { options.once = true ; }
else { options = { once: true } ; }
return this.groupAddListener( emitters , eventName , fn , options ) ;
} ;
// Globally once, only one event could be emitted, by the first emitter to emit
NextGenEvents.groupGlobalOnce = function groupGlobalOnce( emitters , eventName , fn , options )
{
var fnWrapper , triggered = false ;
// Manage arguments
if ( typeof fn !== 'function' ) { options = fn ; fn = undefined ; }
if ( ! options || typeof options !== 'object' ) { options = {} ; }
fn = fn || options.fn ;
delete options.fn ;
// Preserve the listener ID, so groupRemoveListener() will work as expected
options.id = options.id || fn ;
fnWrapper = function() {
if ( triggered ) { return ; }
triggered = true ;
NextGenEvents.groupRemoveListener( emitters , eventName , options.id ) ;
fn.apply( undefined , arguments ) ;
} ;
emitters.forEach( function( emitter ) {
emitter.once( eventName , fnWrapper.bind( undefined , emitter ) , options ) ;
} ) ;
} ;
// Globally once, only one event could be emitted, by the last emitter to emit
NextGenEvents.groupGlobalOnceAll = function groupGlobalOnceAll( emitters , eventName , fn , options )
{
var fnWrapper , triggered = false , count = emitters.length ;
// Manage arguments
if ( typeof fn !== 'function' ) { options = fn ; fn = undefined ; }
if ( ! options || typeof options !== 'object' ) { options = {} ; }
fn = fn || options.fn ;
delete options.fn ;
// Preserve the listener ID, so groupRemoveListener() will work as expected
options.id = options.id || fn ;
fnWrapper = function() {
if ( triggered ) { return ; }
if ( -- count ) { return ; }
// So this is the last emitter...
triggered = true ;
// No need to remove listeners: there are already removed anyway
//NextGenEvents.groupRemoveListener( emitters , eventName , options.id ) ;
fn.apply( undefined , arguments ) ;
} ;
emitters.forEach( function( emitter ) {
emitter.once( eventName , fnWrapper.bind( undefined , emitter ) , options ) ;
} ) ;
} ;
NextGenEvents.groupRemoveListener = function groupRemoveListener( emitters , eventName , id )
{
emitters.forEach( function( emitter ) {
emitter.removeListener( eventName , id ) ;
} ) ;
} ;
NextGenEvents.groupOff = NextGenEvents.groupRemoveListener ;
NextGenEvents.groupRemoveAllListeners = function groupRemoveAllListeners( emitters , eventName )
{
emitters.forEach( function( emitter ) {
emitter.removeAllListeners( eventName ) ;
} ) ;
} ;
NextGenEvents.groupEmit = function groupEmit( emitters )
{
var eventName , nice , argStart = 2 , argEnd , args , count = emitters.length ,
callback , callbackWrapper , callbackTriggered = false ;
if ( typeof arguments[ arguments.length - 1 ] === 'function' )
{
argEnd = -1 ;
callback = arguments[ arguments.length - 1 ] ;
callbackWrapper = function( interruption ) {
if ( callbackTriggered ) { return ; }
if ( interruption )
{
callbackTriggered = true ;
callback( interruption ) ;
}
else if ( ! -- count )
{
callbackTriggered = true ;
callback() ;
}
} ;
}
if ( typeof arguments[ 1 ] === 'number' )
{
argStart = 3 ;
nice = typeof arguments[ 1 ] ;
}
eventName = arguments[ argStart - 1 ] ;
args = Array.prototype.slice.call( arguments , argStart , argEnd ) ;
emitters.forEach( function( emitter ) {
NextGenEvents.emitEvent( {
emitter: emitter ,
name: eventName ,
args: args ,
nice: nice ,
callback: callbackWrapper
} ) ;
} ) ;
} ;
NextGenEvents.groupDefineStates = function groupDefineStates( emitters )
{
var args = Array.prototype.slice.call( arguments , 1 ) ;
emitters.forEach( function( emitter ) {
emitter.defineStates.apply( emitter , args ) ;
} ) ;
} ;
/* Next Gen feature: contexts! */
NextGenEvents.CONTEXT_ENABLED = 0 ;
NextGenEvents.CONTEXT_DISABLED = 1 ;
NextGenEvents.CONTEXT_QUEUED = 2 ;
NextGenEvents.prototype.addListenerContext = function addListenerContext( contextName , options )
{
if ( ! this.__ngev ) { NextGenEvents.init.call( this ) ; }
if ( ! contextName || typeof contextName !== 'string' ) { throw new TypeError( ".addListenerContext(): argument #0 should be a non-empty string" ) ; }
if ( ! options || typeof options !== 'object' ) { options = {} ; }
if ( ! this.__ngev.contexts[ contextName ] )
{
// A context IS an event emitter too!
this.__ngev.contexts[ contextName ] = Object.create( NextGenEvents.prototype ) ;
this.__ngev.contexts[ contextName ].nice = NextGenEvents.SYNC ;
this.__ngev.contexts[ contextName ].ready = true ;
this.__ngev.contexts[ contextName ].status = NextGenEvents.CONTEXT_ENABLED ;
this.__ngev.contexts[ contextName ].serial = false ;
this.__ngev.contexts[ contextName ].queue = [] ;
}
if ( options.nice !== undefined ) { this.__ngev.contexts[ contextName ].nice = Math.floor( options.nice ) ; }
if ( options.status !== undefined ) { this.__ngev.contexts[ contextName ].status = options.status ; }
if ( options.serial !== undefined ) { this.__ngev.contexts[ contextName ].serial = !! options.serial ; }
return this ;
} ;
NextGenEvents.prototype.disableListenerContext = function disableListenerContext( contextName )
{
if ( ! this.__ngev ) { NextGenEvents.init.call( this ) ; }
if ( ! contextName || typeof contextName !== 'string' ) { throw new TypeError( ".disableListenerContext(): argument #0 should be a non-empty string" ) ; }
if ( ! this.__ngev.contexts[ contextName ] ) { this.addListenerContext( contextName ) ; }
this.__ngev.contexts[ contextName ].status = NextGenEvents.CONTEXT_DISABLED ;
return this ;
} ;
NextGenEvents.prototype.enableListenerContext = function enableListenerContext( contextName )
{
if ( ! this.__ngev ) { NextGenEvents.init.call( this ) ; }
if ( ! contextName || typeof contextName !== 'string' ) { throw new TypeError( ".enableListenerContext(): argument #0 should be a non-empty string" ) ; }
if ( ! this.__ngev.contexts[ contextName ] ) { this.addListenerContext( contextName ) ; }
this.__ngev.contexts[ contextName ].status = NextGenEvents.CONTEXT_ENABLED ;
if ( this.__ngev.contexts[ contextName ].queue.length > 0 ) { NextGenEvents.processQueue.call( this , contextName ) ; }
return this ;
} ;
NextGenEvents.prototype.queueListenerContext = function queueListenerContext( contextName )
{
if ( ! this.__ngev ) { NextGenEvents.init.call( this ) ; }
if ( ! contextName || typeof contextName !== 'string' ) { throw new TypeError( ".queueListenerContext(): argument #0 should be a non-empty string" ) ; }
if ( ! this.__ngev.contexts[ contextName ] ) { this.addListenerContext( contextName ) ; }
this.__ngev.contexts[ contextName ].status = NextGenEvents.CONTEXT_QUEUED ;
return this ;
} ;
NextGenEvents.prototype.serializeListenerContext = function serializeListenerContext( contextName , value )
{
if ( ! this.__ngev ) { NextGenEvents.init.call( this ) ; }
if ( ! contextName || typeof contextName !== 'string' ) { throw new TypeError( ".serializeListenerContext(): argument #0 should be a non-empty string" ) ; }
if ( ! this.__ngev.contexts[ contextName ] ) { this.addListenerContext( contextName ) ; }
this.__ngev.contexts[ contextName ].serial = value === undefined ? true : !! value ;
return this ;
} ;
NextGenEvents.prototype.setListenerContextNice = function setListenerContextNice( contextName , nice )
{
if ( ! this.__ngev ) { NextGenEvents.init.call( this ) ; }
if ( ! contextName || typeof contextName !== 'string' ) { throw new TypeError( ".setListenerContextNice(): argument #0 should be a non-empty string" ) ; }
if ( ! this.__ngev.contexts[ contextName ] ) { this.addListenerContext( contextName ) ; }
this.__ngev.contexts[ contextName ].nice = Math.floor( nice ) ;
return this ;
} ;
NextGenEvents.prototype.destroyListenerContext = function destroyListenerContext( contextName )
{
var i , length , eventName , newListeners , removedListeners = [] ;
if ( ! contextName || typeof contextName !== 'string' ) { throw new TypeError( ".disableListenerContext(): argument #0 should be a non-empty string" ) ; }
if ( ! this.__ngev ) { NextGenEvents.init.call( this ) ; }
// We don't care if a context actually exists, all listeners tied to that contextName will be removed
for ( eventName in this.__ngev.listeners )
{
newListeners = null ;
length = this.__ngev.listeners[ eventName ].length ;
for ( i = 0 ; i < length ; i ++ )
{
if ( this.__ngev.listeners[ eventName ][ i ].context === contextName )
{
newListeners = [] ;
removedListeners.push( this.__ngev.listeners[ eventName ][ i ] ) ;
}
else if ( newListeners )
{
newListeners.push( this.__ngev.listeners[ eventName ][ i ] ) ;
}
}
if ( newListeners ) { this.__ngev.listeners[ eventName ] = newListeners ; }
}
if ( this.__ngev.contexts[ contextName ] ) { delete this.__ngev.contexts[ contextName ] ; }
if ( removedListeners.length && this.__ngev.listeners.removeListener.length )
{
this.emit( 'removeListener' , removedListeners ) ;
}
return this ;
} ;
// To be used with .call(), it should not pollute the prototype
NextGenEvents.processQueue = function processQueue( contextName , isCompletionCallback )
{
var context , job ;
// The context doesn't exist anymore, so just abort now
if ( ! this.__ngev.contexts[ contextName ] ) { return ; }
context = this.__ngev.contexts[ contextName ] ;
if ( isCompletionCallback ) { context.ready = true ; }
// Should work on serialization here
//console.log( ">>> " , context ) ;
// Increment recursion
this.__ngev.recursion ++ ;
while ( context.ready && context.queue.length )
{
job = context.queue.shift() ;
// This event has been interrupted, drop it now!
if ( job.event.interrupt ) { continue ; }
try {
if ( job.nice < 0 )
{
if ( this.__ngev.recursion >= - job.nice )
{
setImmediate( NextGenEvents.listenerWrapper.bind( this , job.listener , job.event , context ) ) ;
}
else
{
NextGenEvents.listenerWrapper.call( this , job.listener , job.event , context ) ;
}
}
else
{
setTimeout( NextGenEvents.listenerWrapper.bind( this , job.listener , job.event , context ) , job.nice ) ;
}
}
catch ( error ) {
// Catch error, just to decrement this.__ngev.recursion, re-throw after that...
this.__ngev.recursion -- ;
throw error ;
}
}
// Decrement recursion
this.__ngev.recursion -- ;
} ;
// Backup for the AsyncTryCatch
NextGenEvents.on = NextGenEvents.prototype.on ;
NextGenEvents.once = NextGenEvents.prototype.once ;
NextGenEvents.off = NextGenEvents.prototype.off ;
if ( global.AsyncTryCatch )
{
NextGenEvents.prototype.asyncTryCatchId = global.AsyncTryCatch.NextGenEvents.length ;
global.AsyncTryCatch.NextGenEvents.push( NextGenEvents ) ;
if ( global.AsyncTryCatch.substituted )
{
//console.log( 'live subsitute' ) ;
global.AsyncTryCatch.substitute() ;
}
}
// Load Proxy AT THE END (circular require)
NextGenEvents.Proxy = require( './Proxy.js' ) ;
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"../package.json":5,"./Proxy.js":2}],2:[function(require,module,exports){
/*
Next Gen Events
Copyright (c) 2015 - 2016 Cédric Ronvel
The MIT License (MIT)
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" ;
// Create the object && export it
function Proxy() { return Proxy.create() ; }
module.exports = Proxy ;
var NextGenEvents = require( './NextGenEvents.js' ) ;
var MESSAGE_TYPE = 'NextGenEvents/message' ;
function noop() {}
Proxy.create = function create()
{
var self = Object.create( Proxy.prototype , {
localServices: { value: {} , enumerable: true } ,
remoteServices: { value: {} , enumerable: true } ,
nextAckId: { value: 1 , writable: true , enumerable: true } ,
} ) ;
return self ;
} ;
// Add a local service accessible remotely
Proxy.prototype.addLocalService = function addLocalService( id , emitter , options )
{
this.localServices[ id ] = LocalService.create( this , id , emitter , options ) ;
return this.localServices[ id ] ;
} ;
// Add a remote service accessible locally
Proxy.prototype.addRemoteService = function addRemoteService( id )
{
this.remoteServices[ id ] = RemoteService.create( this , id ) ;
return this.remoteServices[ id ] ;
} ;
// Destroy the proxy
Proxy.prototype.destroy = function destroy()
{
var self = this ;
Object.keys( this.localServices ).forEach( function( id ) {
self.localServices[ id ].destroy() ;
delete self.localServices[ id ] ;
} ) ;
Object.keys( this.remoteServices ).forEach( function( id ) {
self.remoteServices[ id ].destroy() ;
delete self.remoteServices[ id ] ;
} ) ;
this.receive = this.send = noop ;
} ;
// Push an event message.
Proxy.prototype.push = function push( message )
{
if (
message.__type !== MESSAGE_TYPE ||
! message.service || typeof message.service !== 'string' ||
! message.event || typeof message.event !== 'string' ||
! message.method
)
{
return ;
}
switch ( message.method )
{
// Those methods target a remote service
case 'event' :
return this.remoteServices[ message.service ] && this.remoteServices[ message.service ].receiveEvent( message ) ;
case 'ackEmit' :
return this.remoteServices[ message.service ] && this.remoteServices[ message.service ].receiveAckEmit( message ) ;
// Those methods target a local service
case 'emit' :
return this.localServices[ message.service ] && this.localServices[ message.service ].receiveEmit( message ) ;
case 'listen' :
return this.localServices[ message.service ] && this.localServices[ message.service ].receiveListen( message ) ;
case 'ignore' :
return this.localServices[ message.service ] && this.localServices[ message.service ].receiveIgnore( message ) ;
case 'ackEvent' :
return this.localServices[ message.service ] && this.localServices[ message.service ].receiveAckEvent( message ) ;
default:
return ;
}
} ;
// This is the method to receive and decode data from the other side of the communication channel, most of time another proxy.
// In most case, this should be overwritten.
Proxy.prototype.receive = function receive( raw )
{
this.push( raw ) ;
} ;
// This is the method used to send data to the other side of the communication channel, most of time another proxy.
// This MUST be overwritten in any case.
Proxy.prototype.send = function send()
{
throw new Error( 'The send() method of the Proxy MUST be extended/overwritten' ) ;
} ;
/* Local Service */
function LocalService( proxy , id , emitter , options ) { return LocalService.create( proxy , id , emitter , options ) ; }
Proxy.LocalService = LocalService ;
LocalService.create = function create( proxy , id , emitter , options )
{
var self = Object.create( LocalService.prototype , {
proxy: { value: proxy , enumerable: true } ,
id: { value: id , enumerable: true } ,
emitter: { value: emitter , writable: true , enumerable: true } ,
internalEvents: { value: Object.create( NextGenEvents.prototype ) , writable: true , enumerable: true } ,
events: { value: {} , enumerable: true } ,
canListen: { value: !! options.listen , writable: true , enumerable: true } ,
canEmit: { value: !! options.emit , writable: true , enumerable: true } ,
canAck: { value: !! options.ack , writable: true , enumerable: true } ,
canRpc: { value: !! options.rpc , writable: true , enumerable: true } ,
destroyed: { value: false , writable: true , enumerable: true } ,
} ) ;
return self ;
} ;
// Destroy a service
LocalService.prototype.destroy = function destroy()
{
var self = this ;
Object.keys( this.events ).forEach( function( eventName ) {
self.emitter.off( eventName , self.events[ eventName ] ) ;
delete self.events[ eventName ] ;
} ) ;
this.emitter = null ;
this.destroyed = true ;
} ;
// Remote want to emit on the local service
LocalService.prototype.receiveEmit = function receiveEmit( message )
{
if ( this.destroyed || ! this.canEmit || ( message.ack && ! this.canAck ) ) { return ; }
var self = this ;
var event = {
emitter: this.emitter ,
name: message.event ,
args: message.args || []
} ;
if ( message.ack )
{
event.callback = function ack( interruption ) {
self.proxy.send( {
__type: MESSAGE_TYPE ,
service: self.id ,
method: 'ackEmit' ,
ack: message.ack ,
event: message.event ,
interruption: interruption
} ) ;
} ;
}
NextGenEvents.emitEvent( event ) ;
} ;
// Remote want to listen to an event of the local service
LocalService.prototype.receiveListen = function receiveListen( message )
{
if ( this.destroyed || ! this.canListen || ( message.ack && ! this.canAck ) ) { return ; }
if ( message.ack )
{
if ( this.events[ message.event ] )
{
if ( this.events[ message.event ].ack ) { return ; }
// There is already an event, but not featuring ack, remove that listener now
this.emitter.off( message.event , this.events[ message.event ] ) ;
}
this.events[ message.event ] = LocalService.forwardWithAck.bind( this ) ;
this.events[ message.event ].ack = true ;
this.emitter.on( message.event , this.events[ message.event ] , { eventObject: true , async: true } ) ;
}
else
{
if ( this.events[ message.event ] )
{
if ( ! this.events[ message.event ].ack ) { return ; }
// Remote want to downgrade:
// there is already an event, but featuring ack so we remove that listener now
this.emitter.off( message.event , this.events[ message.event ] ) ;
}
this.events[ message.event ] = LocalService.forward.bind( this ) ;
this.events[ message.event ].ack = false ;
this.emitter.on( message.event , this.events[ message.event ] , { eventObject: true } ) ;
}
} ;
// Remote do not want to listen to that event of the local service anymore
LocalService.prototype.receiveIgnore = function receiveIgnore( message )
{
if ( this.destroyed || ! this.canListen ) { return ; }
if ( ! this.events[ message.event ] ) { return ; }
this.emitter.off( message.event , this.events[ message.event ] ) ;
this.events[ message.event ] = null ;
} ;
//
LocalService.prototype.receiveAckEvent = function receiveAckEvent( message )
{
if (
this.destroyed || ! this.canListen || ! this.canAck || ! message.ack ||
! this.events[ message.event ] || ! this.events[ message.event ].ack
)
{
return ;
}
this.internalEvents.emit( 'ack' , message ) ;
} ;
// Send an event from the local service to remote
LocalService.forward = function forward( event )
{
if ( this.destroyed ) { return ; }
this.proxy.send( {
__type: MESSAGE_TYPE ,
service: this.id ,
method: 'event' ,
event: event.name ,
args: event.args
} ) ;
} ;
LocalService.forward.ack = false ;
// Send an event from the local service to remote, with ACK
LocalService.forwardWithAck = function forwardWithAck( event , callback )
{
if ( this.destroyed ) { return ; }
var self = this ;
if ( ! event.callback )
{
// There is no emit callback, no need to ack this one
this.proxy.send( {
__type: MESSAGE_TYPE ,
service: this.id ,
method: 'event' ,
event: event.name ,
args: event.args
} ) ;
callback() ;
return ;
}
var triggered = false ;
var ackId = this.proxy.nextAckId ++ ;
var onAck = function onAck( message ) {
if ( triggered || message.ack !== ackId ) { return ; } // Not our ack...
//if ( message.event !== event ) { return ; } // Do we care?
triggered = true ;
self.internalEvents.off( 'ack' , onAck ) ;
callback() ;
} ;
this.internalEvents.on( 'ack' , onAck ) ;
this.proxy.send( {
__type: MESSAGE_TYPE ,
service: this.id ,
method: 'event' ,
event: event.name ,
ack: ackId ,
args: event.args
} ) ;
} ;
LocalService.forwardWithAck.ack = true ;
/* Remote Service */
function RemoteService( proxy , id ) { return RemoteService.create( proxy , id ) ; }
//RemoteService.prototype = Object.create( NextGenEvents.prototype ) ;
//RemoteService.prototype.constructor = RemoteService ;
Proxy.RemoteService = RemoteService ;
var EVENT_NO_ACK = 1 ;
var EVENT_ACK = 2 ;
RemoteService.create = function create( proxy , id )
{
var self = Object.create( RemoteService.prototype , {
proxy: { value: proxy , enumerable: true } ,
id: { value: id , enumerable: true } ,
// This is the emitter where everything is routed to
emitter: { value: Object.create( NextGenEvents.prototype ) , writable: true , enumerable: true } ,
internalEvents: { value: Object.create( NextGenEvents.prototype ) , writable: true , enumerable: true } ,
events: { value: {} , enumerable: true } ,
destroyed: { value: false , writable: true , enumerable: true } ,
/* Useless for instance, unless some kind of service capabilities discovery mechanism exists
canListen: { value: !! options.listen , writable: true , enumerable: true } ,
canEmit: { value: !! options.emit , writable: true , enumerable: true } ,
canAck: { value: !! options.ack , writable: true , enumerable: true } ,
canRpc: { value: !! options.rpc , writable: true , enumerable: true } ,
*/
} ) ;
return self ;
} ;
// Destroy a service
RemoteService.prototype.destroy = function destroy()
{
var self = this ;
this.emitter.removeAllListeners() ;
this.emitter = null ;
Object.keys( this.events ).forEach( function( eventName ) { delete self.events[ eventName ] ; } ) ;
this.destroyed = true ;
} ;
// Local code want to emit to remote service
RemoteService.prototype.emit = function emit( eventName )
{
if ( this.destroyed ) { return ; }
var self = this , args , callback , ackId , triggered ;
if ( typeof eventName === 'number' ) { throw new TypeError( 'Cannot emit with a nice value on a remote service' ) ; }
if ( typeof arguments[ arguments.length - 1 ] !== 'function' )
{
args = Array.prototype.slice.call( arguments , 1 ) ;
this.proxy.send( {
__type: MESSAGE_TYPE ,
service: this.id ,
method: 'emit' ,
event: eventName ,
args: args
} ) ;
return ;
}
args = Array.prototype.slice.call( arguments , 1 , -1 ) ;
callback = arguments[ arguments.length - 1 ] ;
ackId = this.proxy.nextAckId ++ ;
triggered = false ;
var onAck = function onAck( message ) {
if ( triggered || message.ack !== ackId ) { return ; } // Not our ack...
//if ( message.event !== event ) { return ; } // Do we care?
triggered = true ;
self.internalEvents.off( 'ack' , onAck ) ;
callback( message.interruption ) ;
} ;
this.internalEvents.on( 'ack' , onAck ) ;
this.proxy.send( {
__type: MESSAGE_TYPE ,
service: this.id ,
method: 'emit' ,
ack: ackId ,
event: eventName ,
args: args
} ) ;
} ;
// Local code want to listen to an event of remote service
RemoteService.prototype.addListener = function addListener( eventName , fn , options )
{
if ( this.destroyed ) { return ; }
// Manage arguments the same way NextGenEvents#addListener() does
if ( typeof fn !== 'function' ) { options = fn ; fn = undefined ; }
if ( ! options || typeof options !== 'object' ) { options = {} ; }
options.fn = fn || options.fn ;
this.emitter.addListener( eventName , options ) ;
// No event was added...
if ( ! this.emitter.__ngev.listeners[ eventName ] || ! this.emitter.__ngev.listeners[ eventName ].length ) { return ; }
// If the event is successfully listened to and was not remotely listened...
if ( options.async && this.events[ eventName ] !== EVENT_ACK )
{
// We need to listen to or upgrade this event
this.events[ eventName ] = EVENT_ACK ;
this.proxy.send( {
__type: MESSAGE_TYPE ,
service: this.id ,
method: 'listen' ,
ack: true ,
event: eventName
} ) ;
}
else if ( ! options.async && ! this.events[ eventName ] )
{
// We need to listen to this event
this.events[ eventName ] = EVENT_NO_ACK ;
this.proxy.send( {
__type: MESSAGE_TYPE ,
service: this.id ,
method: 'listen' ,
event: eventName
} ) ;
}
} ;
RemoteService.prototype.on = RemoteService.prototype.addListener ;
// This is a shortcut to this.addListener()
RemoteService.prototype.once = NextGenEvents.prototype.once ;
// Local code want to ignore an event of remote service
RemoteService.prototype.removeListener = function removeListener( eventName , id )
{
if ( this.destroyed ) { return ; }
this.emitter.removeListener( eventName , id ) ;
// If no more listener are locally tied to with event and the event was remotely listened...
if (
( ! this.emitter.__ngev.listeners[ eventName ] || ! this.emitter.__ngev.listeners[ eventName ].length ) &&
this.events[ eventName ]
)
{
this.events[ eventName ] = 0 ;
this.proxy.send( {
__type: MESSAGE_TYPE ,
service: this.id ,
method: 'ignore' ,
event: eventName
} ) ;
}
} ;
RemoteService.prototype.off = RemoteService.prototype.removeListener ;
// A remote service sent an event we are listening to, emit on the service representing the remote
RemoteService.prototype.receiveEvent = function receiveEvent( message )
{
var self = this ;
if ( this.destroyed || ! this.events[ message.event ] ) { return ; }
var event = {
emitter: this.emitter ,
name: message.event ,
args: message.args || []
} ;
if ( message.ack )
{
event.callback = function ack() {
self.proxy.send( {
__type: MESSAGE_TYPE ,
service: self.id ,
method: 'ackEvent' ,
ack: message.ack ,
event: message.event
} ) ;
} ;
}
NextGenEvents.emitEvent( event ) ;
var eventName = event.name ;
// Here we should catch if the event is still listened to ('once' type listeners)
//if ( this.events[ eventName ] ) // not needed, already checked at the begining of the function
if ( ! this.emitter.__ngev.listeners[ eventName ] || ! this.emitter.__ngev.listeners[ eventName ].length )
{
this.events[ eventName ] = 0 ;
this.proxy.send( {
__type: MESSAGE_TYPE ,
service: this.id ,
method: 'ignore' ,
event: eventName
} ) ;
}
} ;
//
RemoteService.prototype.receiveAckEmit = function receiveAckEmit( message )
{
if ( this.destroyed || ! message.ack || this.events[ message.event ] !== EVENT_ACK )
{
return ;
}
this.internalEvents.emit( 'ack' , message ) ;
} ;
},{"./NextGenEvents.js":1}],3:[function(require,module,exports){
/*
Next Gen Events
Copyright (c) 2015 - 2016 Cédric Ronvel
The MIT License (MIT)
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" ;
/* global window */
if ( typeof window.setImmediate !== 'function' )
{
window.setImmediate = function setImmediate( fn ) {
setTimeout( fn , 0 ) ;
} ;
}
module.exports = require( './NextGenEvents.js' ) ;
module.exports.isBrowser = true ;
},{"./NextGenEvents.js":1}],4:[function(require,module,exports){
(function (Buffer){
(function (global, module) {
var exports = module.exports;
/**
* Exports.
*/
module.exports = expect;
expect.Assertion = Assertion;
/**
* Exports version.
*/
expect.version = '0.3.1';
/**
* Possible assertion flags.
*/
var flags = {
not: ['to', 'be', 'have', 'include', 'only']
, to: ['be', 'have', 'include', 'only', 'not']
, only: ['have']
, have: ['own']
, be: ['an']
};
function expect (obj)