text: /*
  Copyright (c) 2010,2011,2012,2013,2014 Morgan Roderick http://roderick.dk
  License: MIT - http://mrgnrdrck.mit-license.org
  
  https://github.com/mroderick/PubSubJS
  */
  (function (root, factory){
  	'use strict';
  
  	var PubSub = {};
  	root.PubSub = PubSub;
  	factory(PubSub);
  
  	// AMD support
  	if (typeof define === 'function' && define.amd){
  		define(function() { return PubSub; });
  
  	// CommonJS and Node.js module support
  	} else if (typeof exports === 'object'){
  		if (module !== undefined && module.exports) {
  			exports = module.exports = PubSub; // Node.js specific `module.exports`
  		}
  		exports.PubSub = PubSub; // CommonJS module 1.1.1 spec
  		module.exports = exports = PubSub; // CommonJS
  	}
  
  }(( typeof window === 'object' && window ) || this, function (PubSub){
  	'use strict';
  
  	var messages = {},
  		lastUid = -1;
  
  	function hasKeys(obj){
  		var key;
  
  		for (key in obj){
  			if ( obj.hasOwnProperty(key) ){
  				return true;
  			}
  		}
  		return false;
  	}
  
  	/**
  	 *	Returns a function that throws the passed exception, for use as argument for setTimeout
  	 *	@param { Object } ex An Error object
  	 */
  	function throwException( ex ){
  		return function reThrowException(){
  			throw ex;
  		};
  	}
  
  	function callSubscriberWithDelayedExceptions( subscriber, message, data ){
  		try {
  			subscriber( message, data );
  		} catch( ex ){
  			setTimeout( throwException( ex ), 0);
  		}
  	}
  
  	function callSubscriberWithImmediateExceptions( subscriber, message, data ){
  		subscriber( message, data );
  	}
  
  	function deliverMessage( originalMessage, matchedMessage, data, immediateExceptions ){
  		var subscribers = messages[matchedMessage],
  			callSubscriber = immediateExceptions ? callSubscriberWithImmediateExceptions : callSubscriberWithDelayedExceptions,
  			s;
  
  		if ( !messages.hasOwnProperty( matchedMessage ) ) {
  			return;
  		}
  
  		for (s in subscribers){
  			if ( subscribers.hasOwnProperty(s)){
  				callSubscriber( subscribers[s], originalMessage, data );
  			}
  		}
  	}
  
  	function createDeliveryFunction( message, data, immediateExceptions ){
  		return function deliverNamespaced(){
  			var topic = String( message ),
  				position = topic.lastIndexOf( '.' );
  
  			// deliver the message as it is now
  			deliverMessage(message, message, data, immediateExceptions);
  
  			// trim the hierarchy and deliver message to each level
  			while( position !== -1 ){
  				topic = topic.substr( 0, position );
  				position = topic.lastIndexOf('.');
  				deliverMessage( message, topic, data, immediateExceptions );
  			}
  		};
  	}
  
  	function messageHasSubscribers( message ){
  		var topic = String( message ),
  			found = Boolean(messages.hasOwnProperty( topic ) && hasKeys(messages[topic])),
  			position = topic.lastIndexOf( '.' );
  
  		while ( !found && position !== -1 ){
  			topic = topic.substr( 0, position );
  			position = topic.lastIndexOf( '.' );
  			found = Boolean(messages.hasOwnProperty( topic ) && hasKeys(messages[topic]));
  		}
  
  		return found;
  	}
  
  	function publish( message, data, sync, immediateExceptions ){
  		var deliver = createDeliveryFunction( message, data, immediateExceptions ),
  			hasSubscribers = messageHasSubscribers( message );
  
  		if ( !hasSubscribers ){
  			return false;
  		}
  
  		if ( sync === true ){
  			deliver();
  		} else {
  			setTimeout( deliver, 0 );
  		}
  		return true;
  	}
  
  	/**
  	 *	PubSub.publish( message[, data] ) -> Boolean
  	 *	- message (String): The message to publish
  	 *	- data: The data to pass to subscribers
  	 *	Publishes the the message, passing the data to it's subscribers
  	**/
  	PubSub.publish = function( message, data ){
  		return publish( message, data, false, PubSub.immediateExceptions );
  	};
  
  	/**
  	 *	PubSub.publishSync( message[, data] ) -> Boolean
  	 *	- message (String): The message to publish
  	 *	- data: The data to pass to subscribers
  	 *	Publishes the the message synchronously, passing the data to it's subscribers
  	**/
  	PubSub.publishSync = function( message, data ){
  		return publish( message, data, true, PubSub.immediateExceptions );
  	};
  
  	/**
  	 *	PubSub.subscribe( message, func ) -> String
  	 *	- message (String): The message to subscribe to
  	 *	- func (Function): The function to call when a new message is published
  	 *	Subscribes the passed function to the passed message. Every returned token is unique and should be stored if
  	 *	you need to unsubscribe
  	**/
  	PubSub.subscribe = function( message, func ){
  		if ( typeof func !== 'function'){
  			return false;
  		}
  
  		// message is not registered yet
  		if ( !messages.hasOwnProperty( message ) ){
  			messages[message] = {};
  		}
  
  		// forcing token as String, to allow for future expansions without breaking usage
  		// and allow for easy use as key names for the 'messages' object
  		var token = 'uid_' + String(++lastUid);
  		messages[message][token] = func;
  
  		// return token for unsubscribing
  		return token;
  	};
  
  	/* Public: Clears all subscriptions
  	 */
  	PubSub.clearAllSubscriptions = function clearAllSubscriptions(){
  		messages = {};
  	};
  
  	/*Public: Clear subscriptions by the topic
  	*/
  	PubSub.clearSubscriptions = function clearSubscriptions(topic){
  		var m;
  		for (m in messages){
  			if (messages.hasOwnProperty(m) && m.indexOf(topic) === 0){
  				delete messages[m];
  			}
  		}
  	};
  
  	/* Public: removes subscriptions.
  	 * When passed a token, removes a specific subscription.
  	 * When passed a function, removes all subscriptions for that function
  	 * When passed a topic, removes all subscriptions for that topic (hierarchy)
  	 *
  	 * value - A token, function or topic to unsubscribe.
  	 *
  	 * Examples
  	 *
  	 *		// Example 1 - unsubscribing with a token
  	 *		var token = PubSub.subscribe('mytopic', myFunc);
  	 *		PubSub.unsubscribe(token);
  	 *
  	 *		// Example 2 - unsubscribing with a function
  	 *		PubSub.unsubscribe(myFunc);
  	 *
  	 *		// Example 3 - unsubscribing a topic
  	 *		PubSub.unsubscribe('mytopic');
  	 */
  	PubSub.unsubscribe = function(value){
  		var descendantTopicExists = function(topic) {
  				var m;
  				for ( m in messages ){
  					if ( messages.hasOwnProperty(m) && m.indexOf(topic) === 0 ){
  						// a descendant of the topic exists:
  						return true;
  					}
  				}
  
  				return false;
  			},
  			isTopic    = typeof value === 'string' && ( messages.hasOwnProperty(value) || descendantTopicExists(value) ),
  			isToken    = !isTopic && typeof value === 'string',
  			isFunction = typeof value === 'function',
  			result = false,
  			m, message, t;
  
  		if (isTopic){
  			PubSub.clearSubscriptions(value);
  			return;
  		}
  
  		for ( m in messages ){
  			if ( messages.hasOwnProperty( m ) ){
  				message = messages[m];
  
  				if ( isToken && message[value] ){
  					delete message[value];
  					result = value;
  					// tokens are unique, so we can just stop here
  					break;
  				}
  
  				if (isFunction) {
  					for ( t in message ){
  						if (message.hasOwnProperty(t) && message[t] === value){
  							delete message[t];
  							result = true;
  						}
  					}
  				}
  			}
  		}
  
  		return result;
  	};
  }));
  