<commit_before>/**
 * Any OOjs UI widget that contains other widgets (such as {@link OO.ui.ButtonWidget buttons} or
 * {@link OO.ui.OptionWidget options}) mixes in GroupElement. Adding, removing, and clearing
 * items from the group is done through the interface the class provides.
 * For more information, please see the [OOjs UI documentation on MediaWiki] [1].
 *
 * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Elements/Groups
 *
 * @abstract
 * @class
 *
 * @constructor
 * @param {Object} [config] Configuration options
 * @cfg {jQuery} [$group] Container node, assigned to #$group, omit to use a generated `<div>`
 */
OO.ui.GroupElement = function OoUiGroupElement( config ) {
	// Configuration initialization
	config = config || {};

	// Properties
	this.$group = null;
	this.items = [];
	this.aggregateItemEvents = {};

	// Initialization
	this.setGroupElement( config.$group || $( '<div>' ) );
};

/* Methods */

/**
 * Set the group element.
 *
 * If an element is already set, items will be moved to the new element.
 *
 * @param {jQuery} $group Element to use as group
 */
OO.ui.GroupElement.prototype.setGroupElement = function ( $group ) {
	var i, len;

	this.$group = $group;
	for ( i = 0, len = this.items.length; i < len; i++ ) {
		this.$group.append( this.items[ i ].$element );
	}
};

/**
 * Check if there are no items.
 *
 * @return {boolean} Group is empty
 */
OO.ui.GroupElement.prototype.isEmpty = function () {
	return !this.items.length;
};

/**
 * Get items.
 *
 * @return {OO.ui.Element[]} Items
 */
OO.ui.GroupElement.prototype.getItems = function () {
	return this.items.slice( 0 );
};

/**
 * Get an item by its data.
 *
 * Data is compared by a hash of its value. Only the first item with matching data will be returned.
 *
 * @param {Object} data Item data to search for
 * @return {OO.ui.Element|null} Item with equivalent data, `null` if none exists
 */
OO.ui.GroupElement.prototype.getItemFromData = function ( data ) {
	var i, len, item,
		hash = OO.getHash( data );

	for ( i = 0, len = this.items.length; i < len; i++ ) {
		item = this.items[ i ];
		if ( hash === OO.getHash( item.getData() ) ) {
			return item;
		}
	}

	return null;
};

/**
 * Get items by their data.
 *
 * Data is compared by a hash of its value. All items with matching data will be returned.
 *
 * @param {Object} data Item data to search for
 * @return {OO.ui.Element[]} Items with equivalent data
 */
OO.ui.GroupElement.prototype.getItemsFromData = function ( data ) {
	var i, len, item,
		hash = OO.getHash( data ),
		items = [];

	for ( i = 0, len = this.items.length; i < len; i++ ) {
		item = this.items[ i ];
		if ( hash === OO.getHash( item.getData() ) ) {
			items.push( item );
		}
	}

	return items;
};

/**
 * Add an aggregate item event.
 *
 * Aggregated events are listened to on each item and then emitted by the group under a new name,
 * and with an additional leading parameter containing the item that emitted the original event.
 * Other arguments that were emitted from the original event are passed through.
 *
 * @param {Object.<string,string|null>} events Aggregate events emitted by group, keyed by item
 *   event, use null value to remove aggregation
 * @throws {Error} If aggregation already exists
 */
OO.ui.GroupElement.prototype.aggregate = function ( events ) {
	var i, len, item, add, remove, itemEvent, groupEvent;

	for ( itemEvent in events ) {
		groupEvent = events[ itemEvent ];

		// Remove existing aggregated event
		if ( Object.prototype.hasOwnProperty.call( this.aggregateItemEvents, itemEvent ) ) {
			// Don't allow duplicate aggregations
			if ( groupEvent ) {
				throw new Error( 'Duplicate item event aggregation for ' + itemEvent );
			}
			// Remove event aggregation from existing items
			for ( i = 0, len = this.items.length; i < len; i++ ) {
				item = this.items[ i ];
				if ( item.connect && item.disconnect ) {
					remove = {};
					remove[ itemEvent ] = [ 'emit', groupEvent, item ];
					item.disconnect( this, remove );
				}
			}
			// Prevent future items from aggregating event
			delete this.aggregateItemEvents[ itemEvent ];
		}

		// Add new aggregate event
		if ( groupEvent ) {
			// Make future items aggregate event
			this.aggregateItemEvents[ itemEvent ] = groupEvent;
			// Add event aggregation to existing items
			for ( i = 0, len = this.items.length; i < len; i++ ) {
				item = this.items[ i ];
				if ( item.connect && item.disconnect ) {
					add = {};
					add[ itemEvent ] = [ 'emit', groupEvent, item ];
					item.connect( this, add );
				}
			}
		}
	}
};

/**
 * Add items.
 *
 * Adding an existing item will move it.
 *
 * @param {OO.ui.Element[]} items Items
 * @param {number} [index] Index to insert items at
 * @chainable
 */
OO.ui.GroupElement.prototype.addItems = function ( items, index ) {
	var i, len, item, event, events, currentIndex,
		itemElements = [];

	for ( i = 0, len = items.length; i < len; i++ ) {
		item = items[ i ];

		// Check if item exists then remove it first, effectively "moving" it
		currentIndex = $.inArray( item, this.items );
		if ( currentIndex >= 0 ) {
			this.removeItems( [ item ] );
			// Adjust index to compensate for removal
			if ( currentIndex < index ) {
				index--;
			}
		}
		// Add the item
		if ( item.connect && item.disconnect && !$.isEmptyObject( this.aggregateItemEvents ) ) {
			events = {};
			for ( event in this.aggregateItemEvents ) {
				events[ event ] = [ 'emit', this.aggregateItemEvents[ event ], item ];
			}
			item.connect( this, events );
		}
		item.setElementGroup( this );
		itemElements.push( item.$element.get( 0 ) );
	}

	if ( index === undefined || index < 0 || index >= this.items.length ) {
		this.$group.append( itemElements );
		this.items.push.apply( this.items, items );
	} else if ( index === 0 ) {
		this.$group.prepend( itemElements );
		this.items.unshift.apply( this.items, items );
	} else {
		this.items[ index ].$element.before( itemElements );
		this.items.splice.apply( this.items, [ index, 0 ].concat( items ) );
	}

	return this;
};

/**
 * Remove items.
 *
 * Items will be detached, not removed, so they can be used later.
 *
 * @param {OO.ui.Element[]} items Items to remove
 * @chainable
 */
OO.ui.GroupElement.prototype.removeItems = function ( items ) {
	var i, len, item, index, remove, itemEvent;

	// Remove specific items
	for ( i = 0, len = items.length; i < len; i++ ) {
		item = items[ i ];
		index = $.inArray( item, this.items );
		if ( index !== -1 ) {
			if (
				item.connect && item.disconnect &&
				!$.isEmptyObject( this.aggregateItemEvents )
			) {
				remove = {};
				if ( Object.prototype.hasOwnProperty.call( this.aggregateItemEvents, itemEvent ) ) {
					remove[ itemEvent ] = [ 'emit', this.aggregateItemEvents[ itemEvent ], item ];
				}
				item.disconnect( this, remove );
			}
			item.setElementGroup( null );
			this.items.splice( index, 1 );
			item.$element.detach();
		}
	}

	return this;
};

/**
 * Clear all items.
 *
 * Items will be detached, not removed, so they can be used later.
 *
 * @chainable
 */
OO.ui.GroupElement.prototype.clearItems = function () {
	var i, len, item, remove, itemEvent;

	// Remove all items
	for ( i = 0, len = this.items.length; i < len; i++ ) {
		item = this.items[ i ];
		if (
			item.connect && item.disconnect &&
			!$.isEmptyObject( this.aggregateItemEvents )
		) {
			remove = {};
			if ( Object.prototype.hasOwnProperty.call( this.aggregateItemEvents, itemEvent ) ) {
				remove[ itemEvent ] = [ 'emit', this.aggregateItemEvents[ itemEvent ], item ];
			}
			item.disconnect( this, remove );
		}
		item.setElementGroup( null );
		item.$element.detach();
	}

	this.items = [];
	return this;
};
<commit_msg>GroupElement: Clarify description<commit_after>/**
 * Any OOjs UI widget that contains other widgets (such as {@link OO.ui.ButtonWidget buttons} or
 * {@link OO.ui.OptionWidget options}) mixes in GroupElement. Adding, removing, and clearing
 * items from the group is done through the interface the class provides.
 * For more information, please see the [OOjs UI documentation on MediaWiki] [1].
 *
 * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Elements/Groups
 *
 * @abstract
 * @class
 *
 * @constructor
 * @param {Object} [config] Configuration options
 * @cfg {jQuery} [$group] The container element created by the class. If this configuration
 *  is omitted, the group element will use a generated `<div>`.
 */
OO.ui.GroupElement = function OoUiGroupElement( config ) {
	// Configuration initialization
	config = config || {};

	// Properties
	this.$group = null;
	this.items = [];
	this.aggregateItemEvents = {};

	// Initialization
	this.setGroupElement( config.$group || $( '<div>' ) );
};

/* Methods */

/**
 * Set the group element.
 *
 * If an element is already set, items will be moved to the new element.
 *
 * @param {jQuery} $group Element to use as group
 */
OO.ui.GroupElement.prototype.setGroupElement = function ( $group ) {
	var i, len;

	this.$group = $group;
	for ( i = 0, len = this.items.length; i < len; i++ ) {
		this.$group.append( this.items[ i ].$element );
	}
};

/**
 * Check if a group contains no items.
 *
 * @return {boolean} Group is empty
 */
OO.ui.GroupElement.prototype.isEmpty = function () {
	return !this.items.length;
};

/**
 * Get all items in the group.
 *
 * The method returns an array of item references (e.g., [button1, button2, button3]) and is useful
 * when synchronizing groups of items, or whenever the references are required (e.g., when removing items
 * from a group).
 *
 * @return {OO.ui.Element[]} An array of items.
 */
OO.ui.GroupElement.prototype.getItems = function () {
	return this.items.slice( 0 );
};

/**
 * Get an item by its data.
 *
 * Only the first item with matching data will be returned. To return all matching items,
 * use the #getItemsFromData method.
 *
 * @param {Object} data Item data to search for
 * @return {OO.ui.Element|null} Item with equivalent data, `null` if none exists
 */
OO.ui.GroupElement.prototype.getItemFromData = function ( data ) {
	var i, len, item,
		hash = OO.getHash( data );

	for ( i = 0, len = this.items.length; i < len; i++ ) {
		item = this.items[ i ];
		if ( hash === OO.getHash( item.getData() ) ) {
			return item;
		}
	}

	return null;
};

/**
 * Get items by their data.
 *
 * All items with matching data will be returned. To return only the first match, use the #getItemFromData method instead.
 *
 * @param {Object} data Item data to search for
 * @return {OO.ui.Element[]} Items with equivalent data
 */
OO.ui.GroupElement.prototype.getItemsFromData = function ( data ) {
	var i, len, item,
		hash = OO.getHash( data ),
		items = [];

	for ( i = 0, len = this.items.length; i < len; i++ ) {
		item = this.items[ i ];
		if ( hash === OO.getHash( item.getData() ) ) {
			items.push( item );
		}
	}

	return items;
};

/**
 * Aggregate the events emitted by the group.
 *
 * When events are aggregated, the group will listen to all contained items for the event,
 * and then emit the event under a new name. The new event will contain an additional leading
 * parameter containing the item that emitted the original event. Other arguments emitted from
 * the original event are passed through.
 *
 * @param {Object.<string,string|null>} events An object keyed by the name of the event that should be
 *  aggregated  (e.g., ‘click’) and the value of the new name to use (e.g., ‘groupClick’).
 *  A `null` value will remove aggregated events.

 * @throws {Error} An error is thrown if aggregation already exists.
 */
OO.ui.GroupElement.prototype.aggregate = function ( events ) {
	var i, len, item, add, remove, itemEvent, groupEvent;

	for ( itemEvent in events ) {
		groupEvent = events[ itemEvent ];

		// Remove existing aggregated event
		if ( Object.prototype.hasOwnProperty.call( this.aggregateItemEvents, itemEvent ) ) {
			// Don't allow duplicate aggregations
			if ( groupEvent ) {
				throw new Error( 'Duplicate item event aggregation for ' + itemEvent );
			}
			// Remove event aggregation from existing items
			for ( i = 0, len = this.items.length; i < len; i++ ) {
				item = this.items[ i ];
				if ( item.connect && item.disconnect ) {
					remove = {};
					remove[ itemEvent ] = [ 'emit', groupEvent, item ];
					item.disconnect( this, remove );
				}
			}
			// Prevent future items from aggregating event
			delete this.aggregateItemEvents[ itemEvent ];
		}

		// Add new aggregate event
		if ( groupEvent ) {
			// Make future items aggregate event
			this.aggregateItemEvents[ itemEvent ] = groupEvent;
			// Add event aggregation to existing items
			for ( i = 0, len = this.items.length; i < len; i++ ) {
				item = this.items[ i ];
				if ( item.connect && item.disconnect ) {
					add = {};
					add[ itemEvent ] = [ 'emit', groupEvent, item ];
					item.connect( this, add );
				}
			}
		}
	}
};

/**
 * Add items to the group.
 *
 * Items will be added to the end of the group array unless the optional `index` parameter specifies
 * a different insertion point. Adding an existing item will move it to the end of the array or the point specified by the `index`.
 *
 * @param {OO.ui.Element[]} items An array of items to add to the group
 * @param {number} [index] Index of the insertion point
 * @chainable
 */
OO.ui.GroupElement.prototype.addItems = function ( items, index ) {
	var i, len, item, event, events, currentIndex,
		itemElements = [];

	for ( i = 0, len = items.length; i < len; i++ ) {
		item = items[ i ];

		// Check if item exists then remove it first, effectively "moving" it
		currentIndex = $.inArray( item, this.items );
		if ( currentIndex >= 0 ) {
			this.removeItems( [ item ] );
			// Adjust index to compensate for removal
			if ( currentIndex < index ) {
				index--;
			}
		}
		// Add the item
		if ( item.connect && item.disconnect && !$.isEmptyObject( this.aggregateItemEvents ) ) {
			events = {};
			for ( event in this.aggregateItemEvents ) {
				events[ event ] = [ 'emit', this.aggregateItemEvents[ event ], item ];
			}
			item.connect( this, events );
		}
		item.setElementGroup( this );
		itemElements.push( item.$element.get( 0 ) );
	}

	if ( index === undefined || index < 0 || index >= this.items.length ) {
		this.$group.append( itemElements );
		this.items.push.apply( this.items, items );
	} else if ( index === 0 ) {
		this.$group.prepend( itemElements );
		this.items.unshift.apply( this.items, items );
	} else {
		this.items[ index ].$element.before( itemElements );
		this.items.splice.apply( this.items, [ index, 0 ].concat( items ) );
	}

	return this;
};

/**
 * Remove the specified items from a group.
 *
 * Removed items are detached (not removed) from the DOM so that they may be reused.
 * To remove all items from a group, you may wish to use the #clearItems method instead.
 *
 * @param {OO.ui.Element[]} items An array of items to remove
 * @chainable
 */
OO.ui.GroupElement.prototype.removeItems = function ( items ) {
	var i, len, item, index, remove, itemEvent;

	// Remove specific items
	for ( i = 0, len = items.length; i < len; i++ ) {
		item = items[ i ];
		index = $.inArray( item, this.items );
		if ( index !== -1 ) {
			if (
				item.connect && item.disconnect &&
				!$.isEmptyObject( this.aggregateItemEvents )
			) {
				remove = {};
				if ( Object.prototype.hasOwnProperty.call( this.aggregateItemEvents, itemEvent ) ) {
					remove[ itemEvent ] = [ 'emit', this.aggregateItemEvents[ itemEvent ], item ];
				}
				item.disconnect( this, remove );
			}
			item.setElementGroup( null );
			this.items.splice( index, 1 );
			item.$element.detach();
		}
	}

	return this;
};

/**
 * Clear all items from the group.
 *
 * Cleared items are detached from the DOM, not removed, so that they may be reused.
 * To remove only a subset of items from a group, use the #removeItems method.
 *
 * @chainable
 */
OO.ui.GroupElement.prototype.clearItems = function () {
	var i, len, item, remove, itemEvent;

	// Remove all items
	for ( i = 0, len = this.items.length; i < len; i++ ) {
		item = this.items[ i ];
		if (
			item.connect && item.disconnect &&
			!$.isEmptyObject( this.aggregateItemEvents )
		) {
			remove = {};
			if ( Object.prototype.hasOwnProperty.call( this.aggregateItemEvents, itemEvent ) ) {
				remove[ itemEvent ] = [ 'emit', this.aggregateItemEvents[ itemEvent ], item ];
			}
			item.disconnect( this, remove );
		}
		item.setElementGroup( null );
		item.$element.detach();
	}

	this.items = [];
	return this;
};
<|endoftext|>


<commit_before>const emptyFunction = function() {}

let handleError = (error, request, response) => {
	console.error(chalk.bold(request.method, request.url))
	console.error(chalk.red(error))

	response.writeHead(500)
	response.end(error.toString())
}

module.exports = function(route, request, response) {
	// Execute handler
	if(this.modifiers.length === 0) {
		try {
			route(request, response)
		} catch(error) {
			handleError(error, request)
		}
	} else {
		let generateNext = index => {
			if(index === this.modifiers.length)
				return route.bind(undefined, request, response, emptyFunction)

			return this.modifiers[index].bind(undefined, request, response, generateNext(index + 1))
		}

		try {
			generateNext(0)()
		} catch(error) {
			handleError(error, request, response)
		}
	}
}<commit_msg>Improved error reporting<commit_after>const emptyFunction = function() {}

let handleError = (error, request, response) => {
	console.error(chalk.bold(request.method, request.url))
	response.writeHead(500)

	if(error.stack) {
		console.error(chalk.red(error.stack))
		response.end(error.stack)
	} else {
		console.error(chalk.red(error))
		response.end(error)
	}
}

module.exports = function(route, request, response) {
	// Execute handler
	if(this.modifiers.length === 0) {
		try {
			route(request, response)
		} catch(error) {
			handleError(error, request)
		}
	} else {
		let generateNext = index => {
			if(index === this.modifiers.length)
				return route.bind(undefined, request, response, emptyFunction)

			return this.modifiers[index].bind(undefined, request, response, generateNext(index + 1))
		}

		try {
			generateNext(0)()
		} catch(error) {
			handleError(error, request, response)
		}
	}
}<|endoftext|>


<commit_before>'use strict';

const EventEmitter = require('events');
const ServiceProvider = require('./ServiceProvider');
const _pick = require('lodash.pick');

class ServiceEmitter extends EventEmitter {

  constructor (opts) {

    // Default value for `opts`.
    opts = opts || {};

    super(); // Call `EventEmitter` constructor.

    /**
     * Will hold object returned by `setInterval` to control service intervals.
     *
     * @private
     * @type {Object}
     */
    this._intervalObject = undefined;

    /**
     * Delay in milliseconds for intervals.
     *
     * @private
     * @constant
     * @type {Number}
     */
    this._delay = opts.delay || 1000;

    /**
     * Determines if {@link this._intervalCallback()} should be called immediately.
     *
     * @private
     * @constant
     * @type {Boolean}
     */
    this._runImmediately = opts.runImmediately || false;

    /**
     * Flag to know if we have to call {@link this.provider.requestData()}
     * automatically or not, default set to true.
     *
     * @private
     * @constant
     * @type {Boolean}
     */
    this._autoRequest = opts.autoRequest || true;

    /**
     * Keeps last data set by provider.
     *
     * @private
     * @type {Object}
     */
    this._data = undefined;

    /**
     * Some implementation of `ServiceProvider`.
     *
     * @private
     * @type {ServiceProvider}
     */
    this.provider = undefined;

    // Listen for new event listeners.
    this.on('newListener', (event, listener) => {

      // We do not handle 'removeListener' here.
      if (event === 'removeListener') { return; }

      // First we make sure `provider` is defined.
      if (!this.isProviderRegistered()) {
        throw new Error('"provider" should be registered before listening any event.');
      }

      // Only 'data' and 'error' events allowed.
      if (event !== 'data' && event !== 'error') {
        throw new Error('For now, only listening "data" and "error" events are allow.');
      }

      // event 'data' is our keyword event name for main process.
      if (event === 'data') {

        // When got first 'data' listener...
        if (!this.dataHasListeners()) {

          // ...set provider to ON.
          this.provider.turnON();

          // Listen for provider 'data' event to be able to transmit the message
          // to custom service emitters.
          this.provider.on('data', data => {

            // Implementation of `onProviderData` should return a `Boolean`
            // indicating if data received from provider is valid or not, if
            // valid then proceed to update `this._data`.
            if (this.onProviderData(data)) {
              this._data = data;
            }
          });

          // Listen provider 'error' event to be able to transmit error to
          // custom service emitters.
          this.provider.on('error', err => this.onProviderError(err));
        }

        // Make sure we are not overriding `_intervalObject`.
        if (this._intervalObject === undefined) {
          this._intervalObject = setInterval(() => this._intervalCallback(), this._delay);

          // Call interval callback NOW if `runImmediately` option is true.
          if (this._runImmediately) {
            this._intervalCallback();
          }
        }
      }

      // Call `onNewListener` for custom behavior.
      this.onNewListener(event, listener);
    });

    // Listen removeListener event.
    this.on('removeListener', (event, listener) => {

      // If no one listens 'data' event then...
      if (!this.dataHasListeners()) {

        // Reset interval.
        clearInterval(this._intervalObject);
        this._intervalObject = undefined;

        // Reset data.
        this._data = undefined;

        // Make sure provider is registered before setting it OFF.
        if (this.isProviderRegistered()) {
          this.provider.turnOFF();

          // Remove all provider listeners, 'data', 'error' and 'wantsData'.
          this.provider.removeAllListeners();
        }
      }

      // Call `onRemoveListener` for custom behavior.
      this.onRemoveListener(event, listener);
    });
  }

  /**
   * Interval callback for {@link this._intervalObject}.
   *
   * @private
   */
  _intervalCallback () {

    // If `this._autoRequest` is true and provider is registered then
    // request data to provider.
    if (this._autoRequest && this.isProviderRegistered()) {
      this.provider.requestData();
    }

    // Call `this.interval()` for custom emitters to know.
    this.interval();
  }

  /**
   * Checks if any listeners listen 'data' event.
   *
   * @return {Boolean} `true` if at least one client listens `data` event.
   */
  dataHasListeners () {
    return this.listenerCount('data') > 0;
  }

  /**
   * Checks if listener provided is listening event name.
   *
   * @param {String} event - Event name to check.
   * @param {Function} listener - Listener to check.
   * @return {Boolean} Whether listener listens event.
   */
  isListeningTo (event, listener) {
    return this.listeners(event).some(_listener => {
      return _listener === listener;
    });
  }

  /**
   * Public method for ServiceProvider registration.
   *
   * @param {ServiceProvider} provider - One of the available providers.
   */
  registerProvider (provider) {

    if (!(provider instanceof ServiceProvider)) {
      throw new Error('"provider" must be an instance of `ServiceProvider`.');
    }

    if (this.isProviderRegistered()) {
      throw new Error('"provider" is already registered!');
    }

    // Do the actual registration.
    this.provider = provider;
  }

  /**
   * Verifies if {@link this.provider} is already registered.
   *
   * @return {Boolean} `true` is registered, `false` otherwise.
   */
  isProviderRegistered () {
    return this.provider && this.provider instanceof ServiceProvider;
  }

  /**
   * Get current provider data with optional pick filter.
   *
   * @param {Array} [pick] - Array of properties to return in Object.
   * @return {Object} Current provider data Object.
   */
  getCurrentData (pick) {
    return !pick ? this._data : _pick(this._data, pick);
  }

  /**
   * Empty `interval` function to be implemented by custom emitter.
   *
   * @abstract
   * @desc This function will be called in each cycle of main interval.
   */
  interval () { }

  /**
   * Empty `onNewListener` function to be implemented by custom emitter.
   *
   * @abstract
   * @desc This function will be called on new event listener.
   * @param {String} event - Event name.
   * @param {Function} listener - Listener Function.
   */
  onNewListener (event, listener) { }

  /**
   * Empty `onRemoveListener` function to be implemented by custom emitter.
   *
   * @abstract
   * @desc This function will be called on remotion of event listener.
   * @param {String} event - Event name.
   * @param {Function} listener - Listener Function.
   */
  onRemoveListener (event, listener) { }

  /**
   * Empty `onProviderData` function to be implemented by custom emitter.
   *
   * @abstract
   * @desc This function will be called when provider emits new data.
   * @param {Object} data - Data to emit.
   * @return {Boolean} Indicates if data received from provider is valid or not.
   *
   * Note: The returned value by the implementation of this method will be used
   * to decide if we should update {@link this._data} with data received or not.
   */
  onProviderData (data) { }

  /**
   * Empty `onProviderError` function to be implemented by custom emitter.
   *
   * @abstract
   * @desc This function will be called when provider emits an error.
   * @param {Object} err - Error to emit.
   */
  onProviderError (err) { }
}

module.exports = ServiceEmitter;
<commit_msg>onProviderData callback<commit_after>'use strict';

const EventEmitter = require('events');
const ServiceProvider = require('./ServiceProvider');
const _pick = require('lodash.pick');

class ServiceEmitter extends EventEmitter {

  constructor (opts) {

    // Default value for `opts`.
    opts = opts || {};

    super(); // Call `EventEmitter` constructor.

    /**
     * Will hold object returned by `setInterval` to control service intervals.
     *
     * @private
     * @type {Object}
     */
    this._intervalObject = undefined;

    /**
     * Delay in milliseconds for intervals.
     *
     * @private
     * @constant
     * @type {Number}
     */
    this._delay = opts.delay || 1000;

    /**
     * Determines if {@link this._intervalCallback()} should be called immediately.
     *
     * @private
     * @constant
     * @type {Boolean}
     */
    this._runImmediately = opts.runImmediately || false;

    /**
     * Flag to know if we have to call {@link this.provider.requestData()}
     * automatically or not, default set to true.
     *
     * @private
     * @constant
     * @type {Boolean}
     */
    this._autoRequest = opts.autoRequest || true;

    /**
     * Keeps last data set by provider.
     *
     * @private
     * @type {Object}
     */
    this._data = undefined;

    /**
     * Some implementation of `ServiceProvider`.
     *
     * @private
     * @type {ServiceProvider}
     */
    this.provider = undefined;

    // Listen for new event listeners.
    this.on('newListener', (event, listener) => {

      // We do not handle 'removeListener' here.
      if (event === 'removeListener') { return; }

      // First we make sure `provider` is defined.
      if (!this.isProviderRegistered()) {
        throw new Error('"provider" should be registered before listening any event.');
      }

      // Only 'data' and 'error' events allowed.
      if (event !== 'data' && event !== 'error') {
        throw new Error('For now, only listening "data" and "error" events are allow.');
      }

      // event 'data' is our keyword event name for main process.
      if (event === 'data') {

        // When got first 'data' listener...
        if (!this.dataHasListeners()) {

          // ...set provider to ON.
          this.provider.turnON();

          // Listen for provider 'data' event to be able to transmit the message
          // to custom service emitters.
          this.provider.on('data', data => {

            // Implementation of `onProviderData` should return a `Boolean`
            // indicating if data received from provider is valid or not, if
            // valid then proceed to update `this._data`.
            if (this.onProviderData(data, this._onProviderDataCallback)) {
              this._data = data;
            }
          });

          // Listen provider 'error' event to be able to transmit error to
          // custom service emitters.
          this.provider.on('error', err => this.onProviderError(err));
        }

        // Make sure we are not overriding `_intervalObject`.
        if (this._intervalObject === undefined) {
          this._intervalObject = setInterval(() => this._intervalCallback(), this._delay);

          // Call interval callback NOW if `runImmediately` option is true.
          if (this._runImmediately) {
            this._intervalCallback();
          }
        }
      }

      // Call `onNewListener` for custom behavior.
      this.onNewListener(event, listener);
    });

    // Listen removeListener event.
    this.on('removeListener', (event, listener) => {

      // If no one listens 'data' event then...
      if (!this.dataHasListeners()) {

        // Reset interval.
        clearInterval(this._intervalObject);
        this._intervalObject = undefined;

        // Reset data.
        this._data = undefined;

        // Make sure provider is registered before setting it OFF.
        if (this.isProviderRegistered()) {
          this.provider.turnOFF();

          // Remove all provider listeners, 'data', 'error' and 'wantsData'.
          this.provider.removeAllListeners();
        }
      }

      // Call `onRemoveListener` for custom behavior.
      this.onRemoveListener(event, listener);
    });
  }

  /**
   * Interval callback for {@link this._intervalObject}.
   *
   * @private
   */
  _intervalCallback () {

    // If `this._autoRequest` is true and provider is registered then
    // request data to provider.
    if (this._autoRequest && this.isProviderRegistered()) {
      this.provider.requestData();
    }

    // Call `this.interval()` for custom emitters to know.
    this.interval();
  }

  /**
   * Callback for onProviderData.
   *
   * @private
   */
  _onProviderDataCallback (error, validatedData) {
    if (error) {
      return this.emit('error', error);
    }

    this._data = validatedData;
    this.emit('data', this._data);
  }

  /**
   * Checks if any listeners listen 'data' event.
   *
   * @return {Boolean} `true` if at least one client listens `data` event.
   */
  dataHasListeners () {
    return this.listenerCount('data') > 0;
  }

  /**
   * Checks if listener provided is listening event name.
   *
   * @param {String} event - Event name to check.
   * @param {Function} listener - Listener to check.
   * @return {Boolean} Whether listener listens event.
   */
  isListeningTo (event, listener) {
    return this.listeners(event).some(_listener => {
      return _listener === listener;
    });
  }

  /**
   * Public method for ServiceProvider registration.
   *
   * @param {ServiceProvider} provider - One of the available providers.
   */
  registerProvider (provider) {

    if (!(provider instanceof ServiceProvider)) {
      throw new Error('"provider" must be an instance of `ServiceProvider`.');
    }

    if (this.isProviderRegistered()) {
      throw new Error('"provider" is already registered!');
    }

    // Do the actual registration.
    this.provider = provider;
  }

  /**
   * Verifies if {@link this.provider} is already registered.
   *
   * @return {Boolean} `true` is registered, `false` otherwise.
   */
  isProviderRegistered () {
    return this.provider && this.provider instanceof ServiceProvider;
  }

  /**
   * Get current provider data with optional pick filter.
   *
   * @param {Array} [pick] - Array of properties to return in Object.
   * @return {Object} Current provider data Object.
   */
  getCurrentData (pick) {
    return !pick ? this._data : _pick(this._data, pick);
  }

  /**
   * Empty `interval` function to be implemented by custom emitter.
   *
   * @abstract
   * @desc This function will be called in each cycle of main interval.
   */
  interval () { }

  /**
   * Empty `onNewListener` function to be implemented by custom emitter.
   *
   * @abstract
   * @desc This function will be called on new event listener.
   * @param {String} event - Event name.
   * @param {Function} listener - Listener Function.
   */
  onNewListener (event, listener) { }

  /**
   * Empty `onRemoveListener` function to be implemented by custom emitter.
   *
   * @abstract
   * @desc This function will be called on remotion of event listener.
   * @param {String} event - Event name.
   * @param {Function} listener - Listener Function.
   */
  onRemoveListener (event, listener) { }

  /**
   * Empty `onProviderData` function to be implemented by custom emitter.
   *
   * @abstract
   * @desc This function will be called when provider emits new data.
   * @param {Object} data - Data to emit.
   * @return {Boolean} Indicates if data received from provider is valid or not.
   *
   * Note: The returned value by the implementation of this method will be used
   * to decide if we should update {@link this._data} with data received or not.
   */
  onProviderData (data, cb) { }

  /**
   * Empty `onProviderError` function to be implemented by custom emitter.
   *
   * @abstract
   * @desc This function will be called when provider emits an error.
   * @param {Object} err - Error to emit.
   */
  onProviderError (err) {
    this.emit('error', error);
  }
}

module.exports = ServiceEmitter;
<|endoftext|>


<commit_before>'use strict';

describe('Controller: MainCtrl', function () {

     //load the controller's module
     beforeEach(module('emuwebApp'));

     var emptyObject = {};

     var MainCtrl, scope, ret, deferred;
     var testSizeAll = 58809;
     var testSizeStart = 10;
     var testSizeEnd = 1337;

     //Initialize the controller and a mock scope
     beforeEach(inject(function ($controller,
                                 $rootScope,
                                 $q,
                                 LevelService,
                                 ConfigProviderService,
                                 viewState,
                                 Soundhandlerservice,
                                 dialogService,
                                 HistoryService,
                                 Iohandlerservice,
                                 Validationservice) {
       scope = $rootScope.$new();
       MainCtrl = $controller('MainCtrl', {
         $scope: scope
       });
       scope.lvl = LevelService;
       scope.vs = viewState;
       scope.cps = ConfigProviderService;
       scope.shs = Soundhandlerservice;
       scope.dialog = dialogService;
       scope.io = Iohandlerservice;
       scope.valid = Validationservice;
       scope.shs.wavJSO.Data = new Array(testSizeAll);
       scope.cps.setVals(defaultEmuwebappConfig);
       scope.cps.curDbConfig = aeDbConfig;
       scope.history = HistoryService;
       deferred = $q.defer();
       deferred.resolve('called');
     }));

     it('should have all variables defined', function () {
       expect(scope.connectBtnLabel).toBe('connect');
       expect(scope.tmp).toEqual(emptyObject);
       expect(scope.dbLoaded).toBe(false);
       expect(scope.is2dCancasesHidden).toBe(true);
       expect(scope.bundleList.length).toBe(0);
       expect(scope.curUserName).toBe('');
       expect(scope.curBndl).toEqual(emptyObject);
       expect(scope.lastclickedutt).toBe(null);
       expect(scope.filterText).toBe('');
       expect(scope.windowWidth).toBeDefined;
       expect(scope.demoDbName).toBe('');
     });

     it('all services should exist', inject(function (viewState,
                                                   ConfigProviderService,
                                                   HistoryService,
                                                   fontScaleService,
                                                   LevelService,
                                                   dialogService,
                                                   Ssffdataservice,
                                                   Soundhandlerservice,
                                                   Drawhelperservice,
                                                   Wavparserservice,
                                                   Iohandlerservice,
                                                   Appcachehandler) {
       expect(viewState).toBeDefined();
       expect(ConfigProviderService).toBeDefined();
       expect(HistoryService).toBeDefined();
       expect(fontScaleService).toBeDefined();
       expect(LevelService).toBeDefined();
       expect(dialogService).toBeDefined();
       expect(Ssffdataservice).toBeDefined();
       expect(Soundhandlerservice).toBeDefined();
       expect(Drawhelperservice).toBeDefined();
       expect(Wavparserservice).toBeDefined();
       expect(Iohandlerservice).toBeDefined();
       expect(Appcachehandler).toBeDefined();

     }));

    it('should have a working uninitialized viewState service', function() {
         expect(scope.vs.curViewPort.sS).toBe(0);
         expect(scope.vs.curViewPort.eS).toBe(0);
         expect(scope.vs.curViewPort.selectS).toBe(-1);
         expect(scope.vs.curViewPort.selectE).toBe(-1);
     });

    it('should resetToInitState', function() {
        scope.resetToInitState();
        expect(scope.curBndl).toEqual(emptyObject);
        expect(scope.bundleList.length).toBe(0);
     });

    it('should clear', function() {
        spyOn(scope.dialog, 'open').and.returnValue(deferred.promise);
        scope.clearBtnClick();
        expect(scope.dialog.open).toHaveBeenCalledWith('views/confirmModal.html', 'ConfirmmodalCtrl', 'Do you wish to clear all loaded data and if connected disconnect from the server? You have NO unsaved changes so no changes will be lost.');
     });

    it('should showHierarchy', function() {
        spyOn(scope.dialog, 'open');
        scope.showHierarchyBtnClick();
        expect(scope.dialog.open).toHaveBeenCalledWith('views/showHierarchyModal.html', 'ShowhierarchyCtrl');
     });

    it('should showAbout', function() {
        spyOn(scope.dialog, 'open');
        scope.aboutBtnClick();
        expect(scope.dialog.open).toHaveBeenCalledWith('views/about.html', 'AboutCtrl');
     });

    it('should openDemoDB ae', inject(function ($q) {
        var ioDeferred = $q.defer();
        ioDeferred.resolve({data: defaultEmuwebappConfig});
        spyOn(scope.vs, 'getPermission').and.returnValue(true);
        spyOn(scope.vs, 'setState');
        spyOn(scope.io, 'getDBconfigFile').and.returnValue(ioDeferred.promise);
        scope.openDemoDBbtnClick('ae');
        expect(scope.vs.setState).toHaveBeenCalledWith('loadingSaving');
        expect(scope.vs.getPermission).toHaveBeenCalledWith('openDemoBtnDBclick');
        expect(scope.demoDbName).toEqual('ae');
        expect(scope.cps.vals.main.comMode).toEqual('DEMO');
        expect(scope.vs.somethingInProgressTxt).toEqual( 'Loading DB config...');
        expect(scope.io.getDBconfigFile).toHaveBeenCalledWith('ae');
     }));

    it('should getPerspectiveColor', function() {
        expect(scope.getPerspectiveColor()).toEqual('emuwebapp-curSelPerspLi');
        // set curPerspectiveIdx
        scope.vs.curPerspectiveIdx = 0;
        expect(scope.getPerspectiveColor({name: 'test'})).toEqual('emuwebapp-perspLi');
        // reset curPerspectiveIdx
        scope.vs.curPerspectiveIdx = -1;
     });

    it('should changePerspective', function() {
        spyOn(scope.vs, 'setRightsubmenuOpen').and.callThrough();
        scope.changePerspective({name: 'default'});
        expect(scope.vs.curPerspectiveIdx).toEqual(0);
        expect(scope.vs.setRightsubmenuOpen).toHaveBeenCalled();
     });

    it('should cmdPlayAll', function() {
        spyOn(scope.vs, 'getPermission').and.returnValue(true);
        spyOn(scope.vs, 'animatePlayHead');
        spyOn(scope.shs, 'playFromTo');
        scope.cmdPlayAll();
        expect(scope.shs.playFromTo).toHaveBeenCalledWith(0,testSizeAll);
        expect(scope.vs.animatePlayHead).toHaveBeenCalledWith(0,testSizeAll);
        expect(scope.vs.getPermission).toHaveBeenCalledWith('playaudio');
     });

    it('should cmdPlaySel', function() {
        scope.vs.select(testSizeStart, testSizeEnd);
        spyOn(scope.vs, 'getPermission').and.returnValue(true);
        spyOn(scope.vs, 'animatePlayHead');
        spyOn(scope.shs, 'playFromTo');
        scope.cmdPlaySel();
        expect(scope.shs.playFromTo).toHaveBeenCalledWith(testSizeStart,testSizeEnd);
        expect(scope.vs.animatePlayHead).toHaveBeenCalledWith(testSizeStart,testSizeEnd);
        expect(scope.vs.getPermission).toHaveBeenCalledWith('playaudio');
     });

    it('should cmdPlayView', function() {
        scope.vs.setViewPort(testSizeStart, testSizeEnd);
        spyOn(scope.vs, 'getPermission').and.returnValue(true);
        spyOn(scope.vs, 'animatePlayHead');
        spyOn(scope.shs, 'playFromTo');
        scope.cmdPlayView();
        expect(scope.shs.playFromTo).toHaveBeenCalledWith(testSizeStart,testSizeEnd);
        expect(scope.vs.animatePlayHead).toHaveBeenCalledWith(testSizeStart,testSizeEnd);
        expect(scope.vs.getPermission).toHaveBeenCalledWith('playaudio');
     });

    it('should cmdZoomSel', function() {
        scope.vs.select(testSizeStart, testSizeEnd);
        spyOn(scope.vs, 'getPermission').and.returnValue(true);
        spyOn(scope.lvl, 'deleteEditArea');
        spyOn(scope.vs, 'setViewPort');
        scope.cmdZoomSel();
        expect(scope.vs.setViewPort).toHaveBeenCalledWith(testSizeStart,testSizeEnd);
        expect(scope.lvl.deleteEditArea).toHaveBeenCalled();
        expect(scope.vs.getPermission).toHaveBeenCalledWith('zoom');
     });

    it('should cmdZoomRight', function() {
        scope.vs.select(testSizeStart, testSizeEnd);
        spyOn(scope.vs, 'getPermission').and.returnValue(true);
        spyOn(scope.lvl, 'deleteEditArea');
        spyOn(scope.vs, 'shiftViewPort');
        scope.cmdZoomRight();
        expect(scope.vs.shiftViewPort).toHaveBeenCalledWith(true);
        expect(scope.lvl.deleteEditArea).toHaveBeenCalled();
        expect(scope.vs.getPermission).toHaveBeenCalledWith('zoom');
     });

    it('should cmdZoomLeft', function() {
        scope.vs.select(testSizeStart, testSizeEnd);
        spyOn(scope.vs, 'getPermission').and.returnValue(true);
        spyOn(scope.lvl, 'deleteEditArea');
        spyOn(scope.vs, 'shiftViewPort');
        scope.cmdZoomLeft();
        expect(scope.vs.shiftViewPort).toHaveBeenCalledWith(false);
        expect(scope.lvl.deleteEditArea).toHaveBeenCalled();
        expect(scope.vs.getPermission).toHaveBeenCalledWith('zoom');
     });

    it('should cmdZoomOut', function() {
        scope.vs.select(testSizeStart, testSizeEnd);
        spyOn(scope.vs, 'getPermission').and.returnValue(true);
        spyOn(scope.lvl, 'deleteEditArea');
        spyOn(scope.vs, 'zoomViewPort');
        scope.cmdZoomOut();
        expect(scope.vs.zoomViewPort).toHaveBeenCalledWith(false);
        expect(scope.lvl.deleteEditArea).toHaveBeenCalled();
        expect(scope.vs.getPermission).toHaveBeenCalledWith('zoom');
     });

    it('should cmdZoomIn', function() {
        scope.vs.select(testSizeStart, testSizeEnd);
        spyOn(scope.vs, 'getPermission').and.returnValue(true);
        spyOn(scope.lvl, 'deleteEditArea');
        spyOn(scope.vs, 'zoomViewPort');
        scope.cmdZoomIn();
        expect(scope.vs.zoomViewPort).toHaveBeenCalledWith(true);
        expect(scope.lvl.deleteEditArea).toHaveBeenCalled();
        expect(scope.vs.getPermission).toHaveBeenCalledWith('zoom');
     });

    it('should cmdZoomAll', function() {
        scope.vs.select(testSizeStart, testSizeEnd);
        spyOn(scope.vs, 'getPermission').and.returnValue(true);
        spyOn(scope.lvl, 'deleteEditArea');
        spyOn(scope.vs, 'setViewPort');
        scope.cmdZoomAll();
        expect(scope.vs.setViewPort).toHaveBeenCalledWith(0, testSizeAll);
        expect(scope.lvl.deleteEditArea).toHaveBeenCalled();
        expect(scope.vs.getPermission).toHaveBeenCalledWith('zoom');
     });
});<commit_msg>improving MainCtrl Unit test<commit_after>'use strict';

describe('Controller: MainCtrl', function () {

     //load the controller's module
     beforeEach(module('emuwebApp'));

     var emptyObject = {};

     var MainCtrl, scope, ret, deferred;
     var testSizeAll = 58809;
     var testSizeStart = 10;
     var testSizeEnd = 1337;

     //Initialize the controller and a mock scope
     beforeEach(inject(function ($controller,
                                 $rootScope,
                                 $q,
                                 $httpBackend,
                                 LevelService,
                                 ConfigProviderService,
                                 viewState,
                                 Soundhandlerservice,
                                 dialogService,
                                 HistoryService,
                                 Iohandlerservice,
                                 Validationservice) {
       scope = $rootScope.$new();
       MainCtrl = $controller('MainCtrl', {
         $scope: scope
       });
       scope.lvl = LevelService;
       scope.vs = viewState;
       scope.cps = ConfigProviderService;
       scope.shs = Soundhandlerservice;
       scope.dialog = dialogService;
       scope.io = Iohandlerservice;
       scope.valid = Validationservice;
       scope.shs.wavJSO.Data = new Array(testSizeAll);
       scope.cps.setVals(defaultEmuwebappConfig);
       scope.cps.curDbConfig = aeDbConfig;
       scope.history = HistoryService;
       deferred = $q.defer();
       deferred.resolve('called');
       $httpBackend.whenGET("schemaFiles/annotationFileSchema.json").respond(annotationFileSchema);
       $httpBackend.whenGET("schemaFiles/emuwebappConfigSchema.json").respond(emuwebappConfigSchema);
       $httpBackend.whenGET("schemaFiles/DBconfigFileSchema.json").respond(DBconfigFileSchema);
       $httpBackend.whenGET("schemaFiles/bundleListSchema.json").respond(bundleListSchema);
       $httpBackend.whenGET("views/error.html").respond('');

     }));

     it('should have all variables defined', function () {
       expect(scope.connectBtnLabel).toBe('connect');
       expect(scope.tmp).toEqual(emptyObject);
       expect(scope.dbLoaded).toBe(false);
       expect(scope.is2dCancasesHidden).toBe(true);
       expect(scope.bundleList.length).toBe(0);
       expect(scope.curUserName).toBe('');
       expect(scope.curBndl).toEqual(emptyObject);
       expect(scope.lastclickedutt).toBe(null);
       expect(scope.filterText).toBe('');
       expect(scope.windowWidth).toBeDefined;
       expect(scope.demoDbName).toBe('');
     });

     it('all services should exist', inject(function (viewState,
                                                   ConfigProviderService,
                                                   HistoryService,
                                                   fontScaleService,
                                                   LevelService,
                                                   dialogService,
                                                   Ssffdataservice,
                                                   Soundhandlerservice,
                                                   Drawhelperservice,
                                                   Wavparserservice,
                                                   Iohandlerservice,
                                                   Appcachehandler) {
       expect(viewState).toBeDefined();
       expect(ConfigProviderService).toBeDefined();
       expect(HistoryService).toBeDefined();
       expect(fontScaleService).toBeDefined();
       expect(LevelService).toBeDefined();
       expect(dialogService).toBeDefined();
       expect(Ssffdataservice).toBeDefined();
       expect(Soundhandlerservice).toBeDefined();
       expect(Drawhelperservice).toBeDefined();
       expect(Wavparserservice).toBeDefined();
       expect(Iohandlerservice).toBeDefined();
       expect(Appcachehandler).toBeDefined();

     }));

    it('should have a working uninitialized viewState service', function() {
         expect(scope.vs.curViewPort.sS).toBe(0);
         expect(scope.vs.curViewPort.eS).toBe(0);
         expect(scope.vs.curViewPort.selectS).toBe(-1);
         expect(scope.vs.curViewPort.selectE).toBe(-1);
     });

    it('should resetToInitState', function() {
        scope.resetToInitState();
        expect(scope.curBndl).toEqual(emptyObject);
        expect(scope.bundleList.length).toBe(0);
     });

    it('should clear', function() {
        spyOn(scope.dialog, 'open').and.returnValue(deferred.promise);
        scope.clearBtnClick();
        expect(scope.dialog.open).toHaveBeenCalledWith('views/confirmModal.html', 'ConfirmmodalCtrl', 'Do you wish to clear all loaded data and if connected disconnect from the server? You have NO unsaved changes so no changes will be lost.');
     });

    it('should showHierarchy', function() {
        spyOn(scope.dialog, 'open');
        scope.showHierarchyBtnClick();
        expect(scope.dialog.open).toHaveBeenCalledWith('views/showHierarchyModal.html', 'ShowhierarchyCtrl');
     });

    it('should showAbout', function() {
        spyOn(scope.dialog, 'open');
        scope.aboutBtnClick();
        expect(scope.dialog.open).toHaveBeenCalledWith('views/about.html', 'AboutCtrl');
     });

    it('should openDemoDB ae', inject(function ($q) {
        var ioDeferred = $q.defer();
        ioDeferred.resolve({data: {EMUwebAppConfig: {}}});
        spyOn(scope.vs, 'getPermission').and.returnValue(true);
        spyOn(scope.vs, 'setState');
        spyOn(scope.io, 'getDBconfigFile').and.returnValue(ioDeferred.promise);
        scope.openDemoDBbtnClick('ae');
        expect(scope.vs.setState).toHaveBeenCalledWith('loadingSaving');
        expect(scope.vs.getPermission).toHaveBeenCalledWith('openDemoBtnDBclick');
        expect(scope.demoDbName).toEqual('ae');
        expect(scope.cps.vals.main.comMode).toEqual('DEMO');
        expect(scope.vs.somethingInProgressTxt).toEqual( 'Loading DB config...');
        expect(scope.io.getDBconfigFile).toHaveBeenCalledWith('ae');
        ioDeferred.resolve();
        scope.$digest();

     }));

    it('should connect', inject(function ($q) {

        var conDeferred = $q.defer();
        conDeferred.resolve('http://test:1234');
        var ioDeferred = $q.defer();
        ioDeferred.resolve({type: 'error'});
        spyOn(scope.vs, 'getPermission').and.returnValue(true);
        spyOn(scope.dialog, 'open').and.returnValue(conDeferred.promise);
        spyOn(scope.io.wsH, 'initConnect').and.returnValue(ioDeferred.promise);
        scope.connectBtnClick();
        expect(scope.vs.getPermission).toHaveBeenCalledWith('connectBtnClick');
        expect(scope.dialog.open).toHaveBeenCalledWith('views/connectModal.html', 'WsconnectionCtrl');
        conDeferred.resolve();
        scope.$digest();
        expect(scope.io.wsH.initConnect).toHaveBeenCalledWith('http://test:1234');
     }));

    it('should getPerspectiveColor', function() {
        expect(scope.getPerspectiveColor()).toEqual('emuwebapp-curSelPerspLi');
        // set curPerspectiveIdx
        scope.vs.curPerspectiveIdx = 0;
        expect(scope.getPerspectiveColor({name: 'test'})).toEqual('emuwebapp-perspLi');
        // reset curPerspectiveIdx
        scope.vs.curPerspectiveIdx = -1;
     });

    it('should changePerspective', function() {
        spyOn(scope.vs, 'setRightsubmenuOpen').and.callThrough();
        scope.changePerspective({name: 'default'});
        expect(scope.vs.curPerspectiveIdx).toEqual(0);
        expect(scope.vs.setRightsubmenuOpen).toHaveBeenCalled();
     });

    it('should cmdPlayAll', function() {
        spyOn(scope.vs, 'getPermission').and.returnValue(true);
        spyOn(scope.vs, 'animatePlayHead');
        spyOn(scope.shs, 'playFromTo');
        scope.cmdPlayAll();
        expect(scope.shs.playFromTo).toHaveBeenCalledWith(0,testSizeAll);
        expect(scope.vs.animatePlayHead).toHaveBeenCalledWith(0,testSizeAll);
        expect(scope.vs.getPermission).toHaveBeenCalledWith('playaudio');
     });

    it('should cmdPlaySel', function() {
        scope.vs.select(testSizeStart, testSizeEnd);
        spyOn(scope.vs, 'getPermission').and.returnValue(true);
        spyOn(scope.vs, 'animatePlayHead');
        spyOn(scope.shs, 'playFromTo');
        scope.cmdPlaySel();
        expect(scope.shs.playFromTo).toHaveBeenCalledWith(testSizeStart,testSizeEnd);
        expect(scope.vs.animatePlayHead).toHaveBeenCalledWith(testSizeStart,testSizeEnd);
        expect(scope.vs.getPermission).toHaveBeenCalledWith('playaudio');
     });

    it('should cmdPlayView', function() {
        scope.vs.setViewPort(testSizeStart, testSizeEnd);
        spyOn(scope.vs, 'getPermission').and.returnValue(true);
        spyOn(scope.vs, 'animatePlayHead');
        spyOn(scope.shs, 'playFromTo');
        scope.cmdPlayView();
        expect(scope.shs.playFromTo).toHaveBeenCalledWith(testSizeStart,testSizeEnd);
        expect(scope.vs.animatePlayHead).toHaveBeenCalledWith(testSizeStart,testSizeEnd);
        expect(scope.vs.getPermission).toHaveBeenCalledWith('playaudio');
     });

    it('should cmdZoomSel', function() {
        scope.vs.select(testSizeStart, testSizeEnd);
        spyOn(scope.vs, 'getPermission').and.returnValue(true);
        spyOn(scope.lvl, 'deleteEditArea');
        spyOn(scope.vs, 'setViewPort');
        scope.cmdZoomSel();
        expect(scope.vs.setViewPort).toHaveBeenCalledWith(testSizeStart,testSizeEnd);
        expect(scope.lvl.deleteEditArea).toHaveBeenCalled();
        expect(scope.vs.getPermission).toHaveBeenCalledWith('zoom');
     });

    it('should cmdZoomRight', function() {
        scope.vs.select(testSizeStart, testSizeEnd);
        spyOn(scope.vs, 'getPermission').and.returnValue(true);
        spyOn(scope.lvl, 'deleteEditArea');
        spyOn(scope.vs, 'shiftViewPort');
        scope.cmdZoomRight();
        expect(scope.vs.shiftViewPort).toHaveBeenCalledWith(true);
        expect(scope.lvl.deleteEditArea).toHaveBeenCalled();
        expect(scope.vs.getPermission).toHaveBeenCalledWith('zoom');
     });

    it('should cmdZoomLeft', function() {
        scope.vs.select(testSizeStart, testSizeEnd);
        spyOn(scope.vs, 'getPermission').and.returnValue(true);
        spyOn(scope.lvl, 'deleteEditArea');
        spyOn(scope.vs, 'shiftViewPort');
        scope.cmdZoomLeft();
        expect(scope.vs.shiftViewPort).toHaveBeenCalledWith(false);
        expect(scope.lvl.deleteEditArea).toHaveBeenCalled();
        expect(scope.vs.getPermission).toHaveBeenCalledWith('zoom');
     });

    it('should cmdZoomOut', function() {
        scope.vs.select(testSizeStart, testSizeEnd);
        spyOn(scope.vs, 'getPermission').and.returnValue(true);
        spyOn(scope.lvl, 'deleteEditArea');
        spyOn(scope.vs, 'zoomViewPort');
        scope.cmdZoomOut();
        expect(scope.vs.zoomViewPort).toHaveBeenCalledWith(false);
        expect(scope.lvl.deleteEditArea).toHaveBeenCalled();
        expect(scope.vs.getPermission).toHaveBeenCalledWith('zoom');
     });

    it('should cmdZoomIn', function() {
        scope.vs.select(testSizeStart, testSizeEnd);
        spyOn(scope.vs, 'getPermission').and.returnValue(true);
        spyOn(scope.lvl, 'deleteEditArea');
        spyOn(scope.vs, 'zoomViewPort');
        scope.cmdZoomIn();
        expect(scope.vs.zoomViewPort).toHaveBeenCalledWith(true);
        expect(scope.lvl.deleteEditArea).toHaveBeenCalled();
        expect(scope.vs.getPermission).toHaveBeenCalledWith('zoom');
     });

    it('should cmdZoomAll', function() {
        scope.vs.select(testSizeStart, testSizeEnd);
        spyOn(scope.vs, 'getPermission').and.returnValue(true);
        spyOn(scope.lvl, 'deleteEditArea');
        spyOn(scope.vs, 'setViewPort');
        scope.cmdZoomAll();
        expect(scope.vs.setViewPort).toHaveBeenCalledWith(0, testSizeAll);
        expect(scope.lvl.deleteEditArea).toHaveBeenCalled();
        expect(scope.vs.getPermission).toHaveBeenCalledWith('zoom');
     });
});<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

jest.dontMock('../Dispatcher');
jest.dontMock('../invariant');
__DEV__ = true; // simulate dev environment to test if errors are thrown

describe('Dispatcher', function() {

  var Dispatcher = require('../Dispatcher');
  var dispatcher;
  var callbackA;
  var callbackB;

  beforeEach(function() {
    dispatcher = new Dispatcher();
    callbackA = jest.genMockFunction();
    callbackB = jest.genMockFunction();
  });

  it('should execute all subscriber callbacks', function() {
    dispatcher.register(callbackA);
    dispatcher.register(callbackB);

    var payload = {};
    dispatcher.dispatch(payload);

    expect(callbackA.mock.calls.length).toBe(1);
    expect(callbackA.mock.calls[0][0]).toBe(payload);

    expect(callbackB.mock.calls.length).toBe(1);
    expect(callbackB.mock.calls[0][0]).toBe(payload);

    dispatcher.dispatch(payload);

    expect(callbackA.mock.calls.length).toBe(2);
    expect(callbackA.mock.calls[1][0]).toBe(payload);

    expect(callbackB.mock.calls.length).toBe(2);
    expect(callbackB.mock.calls[1][0]).toBe(payload);
  });

  it('should wait for callbacks registered earlier', function() {
    var tokenA = dispatcher.register(callbackA);

    dispatcher.register(function(payload) {
      dispatcher.waitFor([tokenA]);
      expect(callbackA.mock.calls.length).toBe(1);
      expect(callbackA.mock.calls[0][0]).toBe(payload);
      callbackB(payload);
    });

    var payload = {};
    dispatcher.dispatch(payload);

    expect(callbackA.mock.calls.length).toBe(1);
    expect(callbackA.mock.calls[0][0]).toBe(payload);

    expect(callbackB.mock.calls.length).toBe(1);
    expect(callbackB.mock.calls[0][0]).toBe(payload);
  });

  it('should wait for callbacks registered later', function() {
    dispatcher.register(function(payload) {
      dispatcher.waitFor([tokenB]);
      expect(callbackB.mock.calls.length).toBe(1);
      expect(callbackB.mock.calls[0][0]).toBe(payload);
      callbackA(payload);
    });

    var tokenB = dispatcher.register(callbackB);

    var payload = {};
    dispatcher.dispatch(payload);

    expect(callbackA.mock.calls.length).toBe(1);
    expect(callbackA.mock.calls[0][0]).toBe(payload);

    expect(callbackB.mock.calls.length).toBe(1);
    expect(callbackB.mock.calls[0][0]).toBe(payload);
  });

  it('should throw if dispatch() while dispatching', function() {
    dispatcher.register(function(payload) {
      dispatcher.dispatch(payload);
      callbackA();
    });

    var payload = {};
    expect(function() {
      dispatcher.dispatch(payload);
    }).toThrow();

    expect(callbackA.mock.calls.length).toBe(0);
  });

  it('should throw if waitFor() while not dispatching', function() {
    var tokenA = dispatcher.register(callbackA);

    expect(function() {
      dispatcher.waitFor([tokenA]);
    }).toThrow();

    expect(callbackA.mock.calls.length).toBe(0);
  });

  it('should throw if waitFor() with invalid token', function() {
    var invalidToken = 1337;

    dispatcher.register(function() {
      dispatcher.waitFor([invalidToken]);
    });

    var payload = {};
    expect(function() {
      dispatcher.dispatch(payload);
    }).toThrow();
  });

  it('should throw on self-circular dependencies', function() {
    var tokenA = dispatcher.register(function() {
      dispatcher.waitFor([tokenA], callbackA);
    });

    var payload = {};
    expect(function() {
      dispatcher.dispatch(payload);
    }).toThrow();

    expect(callbackA.mock.calls.length).toBe(0);
  });

  it('should throw on multi-circular dependencies', function() {
    var tokenA = dispatcher.register(function() {
      dispatcher.waitFor([tokenB], callbackA);
    });

    var tokenB = dispatcher.register(function() {
      dispatcher.waitFor([tokenA], callbackB);
    });

    var payload = {};
    expect(function() {
      dispatcher.dispatch(payload);
    }).toThrow();

    expect(callbackA.mock.calls.length).toBe(0);
    expect(callbackB.mock.calls.length).toBe(0);
  });

  it('should remain in a consistent state after a failed dispatch', function() {
    dispatcher.register(callbackA);
    dispatcher.register(function(payload) {
      if (payload.shouldThrow) {
        throw new Error();
      }
      callbackB();
    });

    expect(function() {
      dispatcher.dispatch({shouldThrow: true});
    }).toThrow();

    // Cannot make assumptions about a failed dispatch.
    var callbackACount = callbackA.mock.calls.length;

    dispatcher.dispatch({shouldThrow: false});

    expect(callbackA.mock.calls.length).toBe(callbackACount + 1);
    expect(callbackB.mock.calls.length).toBe(1);
  });

  it('should properly unregister callbacks', function() {
    dispatcher.register(callbackA);

    var tokenB = dispatcher.register(callbackB);

    var payload = {};
    dispatcher.dispatch(payload);

    expect(callbackA.mock.calls.length).toBe(1);
    expect(callbackA.mock.calls[0][0]).toBe(payload);

    expect(callbackB.mock.calls.length).toBe(1);
    expect(callbackB.mock.calls[0][0]).toBe(payload);

    dispatcher.unregister(tokenB);

    dispatcher.dispatch(payload);

    expect(callbackA.mock.calls.length).toBe(2);
    expect(callbackA.mock.calls[1][0]).toBe(payload);

    expect(callbackB.mock.calls.length).toBe(1);
  });

});
<commit_msg>fixed Dispatcher tests to take one argument for waitFor. closes #82<commit_after>/*
 * Copyright (c) 2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

jest.dontMock('../Dispatcher');
jest.dontMock('../invariant');
__DEV__ = true; // simulate dev environment to test if errors are thrown

describe('Dispatcher', function() {

  var Dispatcher = require('../Dispatcher');
  var dispatcher;
  var callbackA;
  var callbackB;

  beforeEach(function() {
    dispatcher = new Dispatcher();
    callbackA = jest.genMockFunction();
    callbackB = jest.genMockFunction();
  });

  it('should execute all subscriber callbacks', function() {
    dispatcher.register(callbackA);
    dispatcher.register(callbackB);

    var payload = {};
    dispatcher.dispatch(payload);

    expect(callbackA.mock.calls.length).toBe(1);
    expect(callbackA.mock.calls[0][0]).toBe(payload);

    expect(callbackB.mock.calls.length).toBe(1);
    expect(callbackB.mock.calls[0][0]).toBe(payload);

    dispatcher.dispatch(payload);

    expect(callbackA.mock.calls.length).toBe(2);
    expect(callbackA.mock.calls[1][0]).toBe(payload);

    expect(callbackB.mock.calls.length).toBe(2);
    expect(callbackB.mock.calls[1][0]).toBe(payload);
  });

  it('should wait for callbacks registered earlier', function() {
    var tokenA = dispatcher.register(callbackA);

    dispatcher.register(function(payload) {
      dispatcher.waitFor([tokenA]);
      expect(callbackA.mock.calls.length).toBe(1);
      expect(callbackA.mock.calls[0][0]).toBe(payload);
      callbackB(payload);
    });

    var payload = {};
    dispatcher.dispatch(payload);

    expect(callbackA.mock.calls.length).toBe(1);
    expect(callbackA.mock.calls[0][0]).toBe(payload);

    expect(callbackB.mock.calls.length).toBe(1);
    expect(callbackB.mock.calls[0][0]).toBe(payload);
  });

  it('should wait for callbacks registered later', function() {
    dispatcher.register(function(payload) {
      dispatcher.waitFor([tokenB]);
      expect(callbackB.mock.calls.length).toBe(1);
      expect(callbackB.mock.calls[0][0]).toBe(payload);
      callbackA(payload);
    });

    var tokenB = dispatcher.register(callbackB);

    var payload = {};
    dispatcher.dispatch(payload);

    expect(callbackA.mock.calls.length).toBe(1);
    expect(callbackA.mock.calls[0][0]).toBe(payload);

    expect(callbackB.mock.calls.length).toBe(1);
    expect(callbackB.mock.calls[0][0]).toBe(payload);
  });

  it('should throw if dispatch() while dispatching', function() {
    dispatcher.register(function(payload) {
      dispatcher.dispatch(payload);
      callbackA();
    });

    var payload = {};
    expect(function() {
      dispatcher.dispatch(payload);
    }).toThrow();

    expect(callbackA.mock.calls.length).toBe(0);
  });

  it('should throw if waitFor() while not dispatching', function() {
    var tokenA = dispatcher.register(callbackA);

    expect(function() {
      dispatcher.waitFor([tokenA]);
    }).toThrow();

    expect(callbackA.mock.calls.length).toBe(0);
  });

  it('should throw if waitFor() with invalid token', function() {
    var invalidToken = 1337;

    dispatcher.register(function() {
      dispatcher.waitFor([invalidToken]);
    });

    var payload = {};
    expect(function() {
      dispatcher.dispatch(payload);
    }).toThrow();
  });

  it('should throw on self-circular dependencies', function() {
    var tokenA = dispatcher.register(function() {
      dispatcher.waitFor([tokenA]);
    });

    var payload = {};
    expect(function() {
      dispatcher.dispatch(payload);
    }).toThrow();

    expect(callbackA.mock.calls.length).toBe(0);
  });

  it('should throw on multi-circular dependencies', function() {
    var tokenA = dispatcher.register(function() {
      dispatcher.waitFor([tokenB]);
    });

    var tokenB = dispatcher.register(function() {
      dispatcher.waitFor([tokenA]);
    });

    var payload = {};
    expect(function() {
      dispatcher.dispatch(payload);
    }).toThrow();

    expect(callbackA.mock.calls.length).toBe(0);
    expect(callbackB.mock.calls.length).toBe(0);
  });

  it('should remain in a consistent state after a failed dispatch', function() {
    dispatcher.register(callbackA);
    dispatcher.register(function(payload) {
      if (payload.shouldThrow) {
        throw new Error();
      }
      callbackB();
    });

    expect(function() {
      dispatcher.dispatch({shouldThrow: true});
    }).toThrow();

    // Cannot make assumptions about a failed dispatch.
    var callbackACount = callbackA.mock.calls.length;

    dispatcher.dispatch({shouldThrow: false});

    expect(callbackA.mock.calls.length).toBe(callbackACount + 1);
    expect(callbackB.mock.calls.length).toBe(1);
  });

  it('should properly unregister callbacks', function() {
    dispatcher.register(callbackA);

    var tokenB = dispatcher.register(callbackB);

    var payload = {};
    dispatcher.dispatch(payload);

    expect(callbackA.mock.calls.length).toBe(1);
    expect(callbackA.mock.calls[0][0]).toBe(payload);

    expect(callbackB.mock.calls.length).toBe(1);
    expect(callbackB.mock.calls[0][0]).toBe(payload);

    dispatcher.unregister(tokenB);

    dispatcher.dispatch(payload);

    expect(callbackA.mock.calls.length).toBe(2);
    expect(callbackA.mock.calls[1][0]).toBe(payload);

    expect(callbackB.mock.calls.length).toBe(1);
  });

});
<|endoftext|>


<commit_before>/* Copyright (c) Royal Holloway, University of London | Contact Blake Loring (blake@parsed.uk), Duncan Mitchell (Duncan.Mitchell.2015@rhul.ac.uk), or Johannes Kinder (johannes.kinder@rhul.ac.uk) for details or support | LICENSE.md for license details */

const SET_TAG = 'set';
const SEEN_TAG = 'seen';
const MAX_TAG = 'max';

class Stats {

	constructor() {
		this.data = {};
	}

	_entry(title) {

		//Create a new entry if it doesn't exist
		if (!this.data[title]) {
			this.data[title] = {};
		}

		return this.data[title];
	}

	_taggedEntry(title, tag) {
		const entry = this._entry(title);
		entry.tag = tag;
		return entry;
	}

	_getSet(entry) {

		if (!entry.payload) {
			entry.payload = {};
		}

		return entry.payload;
	}

	set(title, item) {
		const entry = this._taggedEntry(title, SET_TAG);
		const set = this._getSet(entry);

		if (set[item]) {
			set[item] += 1;
		} else {
			set[item] = 1;
		}
	}

	seen(title) {
		const entry = this._taggedEntry(title, SEEN_TAG);
		entry.payload = entry.payload ? entry.payload + 1 : 1;
	}

	max(title, val) {
		const entry = this._taggedEntry(title, MAX_TAG);
		entry.payload = entry.payload ? Math.max(entry.payload, val) : val;
	}

	final() {
		return this.data;
	}

	export() {
		return JSON.stringify(this.data);
	}

	_mergeSet(data, title) {
		const pl = data[title].payload;

		for (const i in pl) {
			const entry = this._taggedEntry(title, SET_TAG);
			const set = this._getSet(entry);

			if (!set[i]) {
				set[i] = 0;
			}

			set[i] += pl[i];
		}
	}

	_mergeSeen(data, title) {

		//Just add the two payloads together for num stats
		let entry = this._taggedEntry(title, SEEN_TAG);

		if (!entry.payload) {
			entry.payload = 0;
		}

		entry.payload += data[title].payload;
	}

	_mergeMax(data, title) {
		let entry = this._taggedEntry(title, MAX_TAG);
		entry.payload = entry.payload || 0;
		entry.payload = Math.max(data[title].payload, entry.payload);
	}

	_mergeField(data, title) {
		switch (data[title].tag) {
			case SET_TAG:
				this._mergeSet(data, title);
				break;
			case SEEN_TAG:
				this._mergeSeen(data, title);
				break;
			case MAX_TAG:
				this._mergeMax(data, title);
				break;
			default:
				throw 'Bad Merge';
		}
	}

	merge(data) {
		data = JSON.parse(data);
		for (let entry in data) {
			this._mergeField(data, entry);
		}
	}
}

export default Stats;
<commit_msg>More set work<commit_after>/* Copyright (c) Royal Holloway, University of London | Contact Blake Loring (blake@parsed.uk), Duncan Mitchell (Duncan.Mitchell.2015@rhul.ac.uk), or Johannes Kinder (johannes.kinder@rhul.ac.uk) for details or support | LICENSE.md for license details */

const SET_TAG = 'set';
const SEEN_TAG = 'seen';
const MAX_TAG = 'max';

class Stats {

	constructor() {
		this.data = {};
	}

	_entry(title) {

		//Create a new entry if it doesn't exist
		if (!this.data[title]) {
			this.data[title] = {};
		}

		return this.data[title];
	}

	_taggedEntry(title, tag) {
		const entry = this._entry(title);
		entry.tag = tag;
		return entry;
	}

	_getSet(entry) {

		if (!entry.payload) {
			entry.payload = {};
			delete entry.payload.toString;
		}

		return entry.payload;
	}

	set(title, item) {
		const entry = this._taggedEntry(title, SET_TAG);
		const set = this._getSet(entry);

		if (set[item]) {
			set[item] += 1;
		} else {
			set[item] = 1;
		}
	}

	seen(title) {
		const entry = this._taggedEntry(title, SEEN_TAG);
		entry.payload = entry.payload ? entry.payload + 1 : 1;
	}

	max(title, val) {
		const entry = this._taggedEntry(title, MAX_TAG);
		entry.payload = entry.payload ? Math.max(entry.payload, val) : val;
	}

	final() {
		return this.data;
	}

	export() {
		return JSON.stringify(this.data);
	}

	_mergeSet(data, title) {
		const pl = data[title].payload;

		for (const i in pl) {
			const entry = this._taggedEntry(title, SET_TAG);
			const set = this._getSet(entry);

			if (!set[i]) {
				set[i] = 0;
			}

			set[i] += pl[i];
		}
	}

	_mergeSeen(data, title) {

		//Just add the two payloads together for num stats
		let entry = this._taggedEntry(title, SEEN_TAG);

		if (!entry.payload) {
			entry.payload = 0;
		}

		entry.payload += data[title].payload;
	}

	_mergeMax(data, title) {
		let entry = this._taggedEntry(title, MAX_TAG);
		entry.payload = entry.payload || 0;
		entry.payload = Math.max(data[title].payload, entry.payload);
	}

	_mergeField(data, title) {
		switch (data[title].tag) {
			case SET_TAG:
				this._mergeSet(data, title);
				break;
			case SEEN_TAG:
				this._mergeSeen(data, title);
				break;
			case MAX_TAG:
				this._mergeMax(data, title);
				break;
			default:
				throw 'Bad Merge';
		}
	}

	merge(data) {
		data = JSON.parse(data);
		for (let entry in data) {
			this._mergeField(data, entry);
		}
	}
}

export default Stats;
<|endoftext|>


<commit_before>//v1.0 as Starting Point
//v2.0 Cleaning up code. Setting up Menu Structure and Initial Settings.

var version = '2.0 Beta';
var SCBversion = '3.021'; //Last SandCastle Builder version tested

//Declare and Initialize Variables
var incoming_ONG = 0;
var NinjaAutoClickStatus = 1;
var Time_to_ONG = 1800000;
var lootBoxes = ['boosts', 'ninj', 'cyb', 'hpt', 'bean', 'chron', 'badges', 'badgesav'];

//BB Options Variables
var AudioAlertsStatus = 3;
var audio_Bell = new Audio("http://xenko.comxa.com/Ship_Bell.mp3");
	audio_Bell.volume = 1;
var audio_Chime = new Audio("http://xenko.comxa.com/Chime.mp3");
	audio_Chime.volume = 1;
var BorderAlertStatus = 1;
var description = "Error";
var IdleStatus = 0;
var RKAlertFrequency = 8;
var RKAutoClickStatus = 0;

//RK Variables
var start = -1;
var content = "empty";
var findLocation = '123';
var LCAutoClickStatus = 0;
var LCSolution = 'blank';
var len = 0;
var Logicat = 0;
var oldRKLocation = -1;
var oldRC = Molpy.redactedClicks - 1;
var oldLC = Molpy.Boosts['Logicat'].power - 1;
var RKLevel = '-1';
var RKLocation = '123';
var RKNew = 1;
var RKNewAudio = 1;
var RKTimer = Molpy.redactedToggle - Molpy.redactedCountup;

//Ninja AutoClicker and Border Warnings
function Ninja() {
    if (Molpy.ninjad == 0) {
        if (Molpy.npbONG == 0 && BorderAlertStatus == 1) {
			$("#beach").css("border","4px solid red");
        }
        else {
            incoming_ONG = 0;
            if (NinjaAutoClickStatus == 1) {
                Molpy.ClickBeach();
				Molpy.Notify('Ninja Auto Click', 1);
				if (BorderAlertStatus == 1) {
					$("#beach").css("border","1px solid white");
				}
            }
            else if (BorderAlertStatus == 1) {
            $("#beach").css("border","4px solid green");
            }

        }
	}
    else if (Time_to_ONG <= 15000) {
		if (BorderAlertStatus == 1) {
			$("#beach").css("border","4px solid yellow");
		}
        if (incoming_ONG == 0 && (AudioAlertsStatus == 3 || AudioAlertsStatus == 4)) {
			audio_Chime.play();
			incoming_ONG = 1;
        }
    }
    else if (BorderAlertStatus == 1) {
        $("#beach").css("border","1px solid white");
	}
}

function ToggleMenus(wantOpen) {
	for (i=0, len = lootBoxes.length; i < len; i++) {
		if (lootBoxes[i] == wantOpen) {
			if (!Molpy.options.showhide(lootBoxes[i])) {
				showhideToggle(lootBoxes[i]);
			}
		}
		else {
			if (Molpy.options.showhide(lootBoxes[i])) {
				showhideToggle(lootBoxes[i]);
			}
		}
	}
}

function FindRK() {
	/*
	RV of 1 is Sand Tools
	RV of 2 is Castle Tools
	RV of 3 is Boosts Main Page
	RV of 4 is Boosts Menus, Hill People Tech, etc.
	RV of 5 is Badges Earned
	RV of 6 is Badges Available
	*/

	//Determines RK location, does nothing for locations 1, 2 or 3
	Molpy.Notify('FindRK Run', 1);
	findLocation = '123';
	if (Molpy.redactedVisible == 4) {
		findLocation = Molpy.redactedGr;
	}
	else if (Molpy.redactedVisible == 5) {
		findLocation = 'badges';
	}
	else if (Molpy.redactedVisible == 6) {
		findLocation = 'badgesav';
	}

	//Opens RK location if not already open
	if (findLocation != '123' && !Molpy.options.showhide[findLocation]) {
		showhideToggle(findLocation);
	}

	//Resets old RK variables
	oldRKLocation = Molpy.redactedVisible;
	oldRC = Molpy.redactedClicks;
	oldLC = Molpy.Boosts['Logicat'].power;
	return findLocation;
}

function RedundaKitty() {
	//Refresh Timer Variable
	RKTimer = Molpy.redactedToggle - Molpy.redactedCountup;
	RKLocation = '123';

	//If a RedundaKitty is available
	if (Molpy.redactedVisible > 0) {

		//If RK is new, find it.
		if (RKNew == 1 || Molpy.redactedVisible != oldRKLocation || Molpy.redactedClicks > oldRC || Molpy.Boosts['Logicat'].power != oldLC) {
			RKLocation = FindRK();
			RKNewAudio = 1;
			RKNew = 0;
		}

		//Determines if it is an RK or LC, and also highlights it
		Molpy.Notify($('#redacteditem').length, 1);
		if ($('#redacteditem').length) {
			$('#redacteditem').css("border","2px solid red");
			content = $('#redacteditem').html();
			if (content.indexOf("statement") !== -1) {
				Logicat = 1;
			}
			else {
				Logicat = 0;
				start = content.indexOf("ClickRedacted");
				content = content.substring(start,start+17);
				content = content.replace(/[&\/\\#,+()$~%.'":*?<>{}]/g,'');
				len = content.length;
				RKLevel = content.substring(13,len);
				if (RKLevel != 1) {
					Molpy.Notify('RedundaKitty Level is: ' + RKLevel, 1);
				}
			}
		}
		else {
			Molpy.Notify('RedundaKitty/Logicat Not Found', 1);
			Logicat = 99;
		}

		//Clicks RK if AutoClick Enabled
		if (RKAutoClickStatus == 1 && Logicat == 0 ) {
			Molpy.ClickRedacted(RKLevel);
			RKNew = 1;
			if (RKLocation != '123') {
				showhideToggle(RKLocation);
				RKLocation = '123';
			}
		}
		//Solves and Click LC if AutoClick Enabled
		else if (LCAutoClickStatus == 1 && Logicat == 1) {
			Logicat();
			RKNew = 1;
			if (RKLocation != '123') {
				showhideToggle(RKLocation);
				RKLocation = '123';
			}
		}
		//Redundakitty Notifications for Manual Clicking (Title Bar, Audio)
		else {
			document.title = "! kitten !";
			if (Math.floor(RKTimer % RKAlertFrequency) == 0 && (AudioAlertsStatus == 1 || AudioAlertsStatus == 3)) {
				audio_Bell.play();
			}
		}
	}
	else {
		document.title = RKTimer;
		oldRKLocation = -1;
		if (RKNew != 1) {
			RKNew = 1;
		}
	}
}

function Logicat() {
	var i = 65;
	do
		{LCSolution = String.fromCharCode(i);
		i++;}
	while (Molpy.redactedPuzzleTarget != Molpy.redactedSGen.StatementValue(LCSolution));
	Molpy.ClickRedactedPuzzle(LCSolution);

	/*while (Molpy.redactedPuzzleTarget != undefined) {
		LCSolution = String.fromCharCode(i);
		if (Molpy.redactedPuzzleTarget == Molpy.redactedSGen.StatementValue(LCSolution)) {
			Molpy.ClickRedactedPuzzle(LCSolution);
			Molpy.redactedPuzzleTarget = undefined;
		}
		else {i++;}
	}*/
}

function SwitchOption(option) {
	switch (option) {
		case 'RKAutoClick':
			RKAutoClickStatus++;
			if (RKAutoClickStatus > 1) {RKAutoClickStatus = 0;}
			status = RKAutoClickStatus;
			break;
		case 'LCAutoClick':
			LCAutoClickStatus++;
			if (LCAutoClickStatus > 1) {LCAutoClickStatus = 0;}
			status = LCAutoClickStatus;
			break;
		case 'NinjaAutoClick':
			NinjaAutoClickStatus++;
			if (NinjaAutoClickStatus > 1) {NinjaAutoClickStatus = 0;}
			status = NinjaAutoClickStatus;
			break;
		case 'BorderAlert':
			BorderAlertStatus++;
			if (BorderAlertStatus > 1) {
				BorderAlertStatus = 0;
				$("#beach").css("border","1px solid white");
			}
			status = BorderAlertStatus;
			break;
		case 'AudioAlerts':
			AudioAlertsStatus++;
			if (AudioAlertsStatus > 3) {AudioAlertsStatus = 0;}
			status = AudioAlertsStatus;
			break;
	}
	DisplayDescription(option, status);
}

function DisplayDescription(option, status) {
	error = 0;
	if (option == 'RKAutoClick' || option == 'LCAutoClick' || option == 'NinjaAutoClick' || option == 'BorderAlert') {
		if (status == 0) {description = 'Off';}
		else if (status == 1) {description = 'On';}
		else {Molpy.Notify('Display Description Error',1);}
	}
	else if (option == 'AudioAlerts') {
		if (status == 0) {description = 'Off';}
		else if (status == 1) {description = 'RK Only';}
		else if (status == 2) {description = 'ONG Only';}
		else if (status == 3) {description = 'RK and ONG';}
		else {Molpy.Notify('Display Description Error - Audio Alerts: ' + status,1);}
	}
	else {
		Molpy.Notify(option + ' is not a valid option', 1);
		error = 1;
	}

	if (error == 0) {g(option + 'Desc').innerHTML = '
' + description;}
}

//Beach Ball Startup
//Set Settings
if (Molpy.Got('Kitnip') == 1){RKAlertFrequency = 10;}

//Create Menu
$('#optionsItems').append('

BeachBall Settings

');
$('#optionsItems').append('

Redundakitty Auto Click

');
$('#optionsItems').append('

Logicat Auto Click

');
$('#optionsItems').append('

Ninja Auto Click

');
$('#optionsItems').append('

Ninja Visual Alert

');
$('#optionsItems').append('

Audio Alerts

');
$('#optionsItems').append('

Spawn RK

');
$('#optionsItems').append('

Spawn RK

');
DisplayDescription('RKAutoClick', RKAutoClickStatus);
DisplayDescription('LCAutoClick', LCAutoClickStatus);
DisplayDescription('NinjaAutoClick', NinjaAutoClickStatus);
DisplayDescription('BorderAlert', BorderAlertStatus);
DisplayDescription('AudioAlerts', AudioAlertsStatus);

function MainLoop() {
	Molpy.Notify('BeachBall version ' + version + ' loaded for SandCastle Builder version ' + SCBversion, 1);
	setInterval(function() {
		//Molpy.Notify('1 mNP', 0);
		Time_to_ONG = (Molpy.NPlength * 1000) - Molpy.ONGelapsed;
		RedundaKitty();
		Ninja();
	}, 1800);
}

//Run Main Loop after 1 second startup delay
setTimeout(MainLoop, 1000);

function SpawnRK() {
	Molpy.redactedCountup = Molpy.redactedToggle - 1;
}

<commit_msg>Toggle Menus Function Bug Fix<commit_after>//v1.0 as Starting Point
//v2.0 Cleaning up code. Setting up Menu Structure and Initial Settings.

var version = '2.0 Beta';
var SCBversion = '3.021'; //Last SandCastle Builder version tested

//Declare and Initialize Variables
var incoming_ONG = 0;
var NinjaAutoClickStatus = 1;
var Time_to_ONG = 1800000;
var lootBoxes = ['boosts', 'ninj', 'cyb', 'hpt', 'bean', 'chron', 'badges', 'badgesav'];

//BB Options Variables
var AudioAlertsStatus = 3;
var audio_Bell = new Audio("http://xenko.comxa.com/Ship_Bell.mp3");
	audio_Bell.volume = 1;
var audio_Chime = new Audio("http://xenko.comxa.com/Chime.mp3");
	audio_Chime.volume = 1;
var BorderAlertStatus = 1;
var description = "Error";
var IdleStatus = 0;
var RKAlertFrequency = 8;
var RKAutoClickStatus = 0;

//RK Variables
var start = -1;
var content = "empty";
var findLocation = '123';
var LCAutoClickStatus = 0;
var LCSolution = 'blank';
var len = 0;
var Logicat = 0;
var oldRKLocation = -1;
var oldRC = Molpy.redactedClicks - 1;
var oldLC = Molpy.Boosts['Logicat'].power - 1;
var RKLevel = '-1';
var RKLocation = '123';
var RKNew = 1;
var RKNewAudio = 1;
var RKTimer = Molpy.redactedToggle - Molpy.redactedCountup;

//Ninja AutoClicker and Border Warnings
function Ninja() {
    if (Molpy.ninjad == 0) {
        if (Molpy.npbONG == 0 && BorderAlertStatus == 1) {
			$("#beach").css("border","4px solid red");
        }
        else {
            incoming_ONG = 0;
            if (NinjaAutoClickStatus == 1) {
                Molpy.ClickBeach();
				Molpy.Notify('Ninja Auto Click', 1);
				if (BorderAlertStatus == 1) {
					$("#beach").css("border","1px solid white");
				}
            }
            else if (BorderAlertStatus == 1) {
            $("#beach").css("border","4px solid green");
            }

        }
	}
    else if (Time_to_ONG <= 15000) {
		if (BorderAlertStatus == 1) {
			$("#beach").css("border","4px solid yellow");
		}
        if (incoming_ONG == 0 && (AudioAlertsStatus == 3 || AudioAlertsStatus == 4)) {
			audio_Chime.play();
			incoming_ONG = 1;
        }
    }
    else if (BorderAlertStatus == 1) {
        $("#beach").css("border","1px solid white");
	}
}

function ToggleMenus(wantOpen) {
	for (i=0, len = lootBoxes.length; i < len; i++) {
		if (lootBoxes[i] == wantOpen) {
			Molpy.Notify(Molpy.options.showhide(lootBoxes[i]), 1);
			if (Molpy.options.showhide(lootBoxes[i])) {
				showhideToggle(lootBoxes[i]);
			}
		}
		else {
			if (Molpy.options.showhide(lootBoxes[i])) {
				showhideToggle(lootBoxes[i]);
			}
		}
	}
}

function FindRK() {
	/*
	RV of 1 is Sand Tools
	RV of 2 is Castle Tools
	RV of 3 is Boosts Main Page
	RV of 4 is Boosts Menus, Hill People Tech, etc.
	RV of 5 is Badges Earned
	RV of 6 is Badges Available
	*/

	//Determines RK location, does nothing for locations 1, 2 or 3
	Molpy.Notify('FindRK Run', 1);
	findLocation = '123';
	if (Molpy.redactedVisible == 4) {
		findLocation = Molpy.redactedGr;
	}
	else if (Molpy.redactedVisible == 5) {
		findLocation = 'badges';
	}
	else if (Molpy.redactedVisible == 6) {
		findLocation = 'badgesav';
	}

	//Opens RK location if not already open
	if (findLocation != '123' && !Molpy.options.showhide[findLocation]) {
		showhideToggle(findLocation);
	}

	//Resets old RK variables
	oldRKLocation = Molpy.redactedVisible;
	oldRC = Molpy.redactedClicks;
	oldLC = Molpy.Boosts['Logicat'].power;
	return findLocation;
}

function RedundaKitty() {
	//Refresh Timer Variable
	RKTimer = Molpy.redactedToggle - Molpy.redactedCountup;
	RKLocation = '123';

	//If a RedundaKitty is available
	if (Molpy.redactedVisible > 0) {

		//If RK is new, find it.
		if (RKNew == 1 || Molpy.redactedVisible != oldRKLocation || Molpy.redactedClicks > oldRC || Molpy.Boosts['Logicat'].power != oldLC) {
			RKLocation = FindRK();
			RKNewAudio = 1;
			RKNew = 0;
		}

		//Determines if it is an RK or LC, and also highlights it
		Molpy.Notify($('#redacteditem').length, 1);
		if ($('#redacteditem').length) {
			$('#redacteditem').css("border","2px solid red");
			content = $('#redacteditem').html();
			if (content.indexOf("statement") !== -1) {
				Logicat = 1;
			}
			else {
				Logicat = 0;
				start = content.indexOf("ClickRedacted");
				content = content.substring(start,start+17);
				content = content.replace(/[&\/\\#,+()$~%.'":*?<>{}]/g,'');
				len = content.length;
				RKLevel = content.substring(13,len);
				if (RKLevel != 1) {
					Molpy.Notify('RedundaKitty Level is: ' + RKLevel, 1);
				}
			}
		}
		else {
			Molpy.Notify('RedundaKitty/Logicat Not Found', 1);
			Logicat = 99;
		}

		//Clicks RK if AutoClick Enabled
		if (RKAutoClickStatus == 1 && Logicat == 0 ) {
			Molpy.ClickRedacted(RKLevel);
			RKNew = 1;
			if (RKLocation != '123') {
				showhideToggle(RKLocation);
				RKLocation = '123';
			}
		}
		//Solves and Click LC if AutoClick Enabled
		else if (LCAutoClickStatus == 1 && Logicat == 1) {
			Logicat();
			RKNew = 1;
			if (RKLocation != '123') {
				showhideToggle(RKLocation);
				RKLocation = '123';
			}
		}
		//Redundakitty Notifications for Manual Clicking (Title Bar, Audio)
		else {
			document.title = "! kitten !";
			if (Math.floor(RKTimer % RKAlertFrequency) == 0 && (AudioAlertsStatus == 1 || AudioAlertsStatus == 3)) {
				audio_Bell.play();
			}
		}
	}
	else {
		document.title = RKTimer;
		oldRKLocation = -1;
		if (RKNew != 1) {
			RKNew = 1;
		}
	}
}

function Logicat() {
	var i = 65;
	do
		{LCSolution = String.fromCharCode(i);
		i++;}
	while (Molpy.redactedPuzzleTarget != Molpy.redactedSGen.StatementValue(LCSolution));
	Molpy.ClickRedactedPuzzle(LCSolution);

	/*while (Molpy.redactedPuzzleTarget != undefined) {
		LCSolution = String.fromCharCode(i);
		if (Molpy.redactedPuzzleTarget == Molpy.redactedSGen.StatementValue(LCSolution)) {
			Molpy.ClickRedactedPuzzle(LCSolution);
			Molpy.redactedPuzzleTarget = undefined;
		}
		else {i++;}
	}*/
}

function SwitchOption(option) {
	switch (option) {
		case 'RKAutoClick':
			RKAutoClickStatus++;
			if (RKAutoClickStatus > 1) {RKAutoClickStatus = 0;}
			status = RKAutoClickStatus;
			break;
		case 'LCAutoClick':
			LCAutoClickStatus++;
			if (LCAutoClickStatus > 1) {LCAutoClickStatus = 0;}
			status = LCAutoClickStatus;
			break;
		case 'NinjaAutoClick':
			NinjaAutoClickStatus++;
			if (NinjaAutoClickStatus > 1) {NinjaAutoClickStatus = 0;}
			status = NinjaAutoClickStatus;
			break;
		case 'BorderAlert':
			BorderAlertStatus++;
			if (BorderAlertStatus > 1) {
				BorderAlertStatus = 0;
				$("#beach").css("border","1px solid white");
			}
			status = BorderAlertStatus;
			break;
		case 'AudioAlerts':
			AudioAlertsStatus++;
			if (AudioAlertsStatus > 3) {AudioAlertsStatus = 0;}
			status = AudioAlertsStatus;
			break;
	}
	DisplayDescription(option, status);
}

function DisplayDescription(option, status) {
	error = 0;
	if (option == 'RKAutoClick' || option == 'LCAutoClick' || option == 'NinjaAutoClick' || option == 'BorderAlert') {
		if (status == 0) {description = 'Off';}
		else if (status == 1) {description = 'On';}
		else {Molpy.Notify('Display Description Error',1);}
	}
	else if (option == 'AudioAlerts') {
		if (status == 0) {description = 'Off';}
		else if (status == 1) {description = 'RK Only';}
		else if (status == 2) {description = 'ONG Only';}
		else if (status == 3) {description = 'RK and ONG';}
		else {Molpy.Notify('Display Description Error - Audio Alerts: ' + status,1);}
	}
	else {
		Molpy.Notify(option + ' is not a valid option', 1);
		error = 1;
	}

	if (error == 0) {g(option + 'Desc').innerHTML = '
' + description;}
}

//Beach Ball Startup
//Set Settings
if (Molpy.Got('Kitnip') == 1){RKAlertFrequency = 10;}

//Create Menu
$('#optionsItems').append('

BeachBall Settings

');
$('#optionsItems').append('

Redundakitty Auto Click

');
$('#optionsItems').append('

Logicat Auto Click

');
$('#optionsItems').append('

Ninja Auto Click

');
$('#optionsItems').append('

Ninja Visual Alert

');
$('#optionsItems').append('

Audio Alerts

');
$('#optionsItems').append('

Spawn RK

');
$('#optionsItems').append('

Toggle Boosts

');
DisplayDescription('RKAutoClick', RKAutoClickStatus);
DisplayDescription('LCAutoClick', LCAutoClickStatus);
DisplayDescription('NinjaAutoClick', NinjaAutoClickStatus);
DisplayDescription('BorderAlert', BorderAlertStatus);
DisplayDescription('AudioAlerts', AudioAlertsStatus);

function MainLoop() {
	Molpy.Notify('BeachBall version ' + version + ' loaded for SandCastle Builder version ' + SCBversion, 1);
	setInterval(function() {
		//Molpy.Notify('1 mNP', 0);
		Time_to_ONG = (Molpy.NPlength * 1000) - Molpy.ONGelapsed;
		RedundaKitty();
		Ninja();
	}, 1800);
}

//Run Main Loop after 1 second startup delay
setTimeout(MainLoop, 1000);

function SpawnRK() {
	Molpy.redactedCountup = Molpy.redactedToggle - 1;
}

<|endoftext|>


<commit_before>var assert = require("assert");
var helper = require('../../lib/template-helpers/templateS3Url');
var async = require('async');

describe('templateS3Url', function(){

    async.each([
        {
            description: 'should resolve http path on windows',
            particlePath: 'particles\\cftemplates\\example.template',
            expected:  'https://s3-eu-west-1.amazonaws.com/bucket/particles/cftemplates/example.template'
        },
        {
            description: 'should resolve http path on linux',
            particlePath: 'particles/cftemplates/example.template',
            expected:  'https://s3-eu-west-1.amazonaws.com/bucket/particles/cftemplates/example.template'
        }
    ], function(config){

        it(config.description, function(done){

            //var root = {s3: {awsPath: 'https://s3-eu-west-1.amazonaws.com/bucket/', awsPathInS3Format: 's3://bucket/'}};
            var root = {
              s3: {
                condensationUrl: {
                  protocol: 'https:',
                  slashes: true,
                  auth: null,
                  host: 's3-eu-west-1.amazonaws.com',
                  port: null,
                  hostname: 's3-eu-west-1.amazonaws.com',
                  hash: null,
                  search: null,
                  query: null,
                  pathname: '/bucket/',
                  path: '/bucket/',
                  href: 'https://s3-eu-west-1.amazonaws.com//bucket/'
                }
              }
            };

            //Arrange
            var hOpts = {
                data: {_file: null, root: root},
                hash: {}
            };
            var cOpts = {
                particleLoader: {
                    loadParticle: function(){
                        return {relative: config.particlePath};
                    }
                }
            };

            //Act
            var result = helper.helper.apply(root, [null, null, null, hOpts, cOpts]);

            //Assert
            assert.equal(result, config.expected);
            done();
        });

    });

});
<commit_msg>remove comment<commit_after>var assert = require("assert");
var helper = require('../../lib/template-helpers/templateS3Url');
var async = require('async');

describe('templateS3Url', function(){

    async.each([
        {
            description: 'should resolve http path on windows',
            particlePath: 'particles\\cftemplates\\example.template',
            expected:  'https://s3-eu-west-1.amazonaws.com/bucket/particles/cftemplates/example.template'
        },
        {
            description: 'should resolve http path on linux',
            particlePath: 'particles/cftemplates/example.template',
            expected:  'https://s3-eu-west-1.amazonaws.com/bucket/particles/cftemplates/example.template'
        }
    ], function(config){

        it(config.description, function(done){

            var root = {
              s3: {
                condensationUrl: {
                  protocol: 'https:',
                  slashes: true,
                  auth: null,
                  host: 's3-eu-west-1.amazonaws.com',
                  port: null,
                  hostname: 's3-eu-west-1.amazonaws.com',
                  hash: null,
                  search: null,
                  query: null,
                  pathname: '/bucket/',
                  path: '/bucket/',
                  href: 'https://s3-eu-west-1.amazonaws.com//bucket/'
                }
              }
            };

            //Arrange
            var hOpts = {
                data: {_file: null, root: root},
                hash: {}
            };
            var cOpts = {
                particleLoader: {
                    loadParticle: function(){
                        return {relative: config.particlePath};
                    }
                }
            };

            //Act
            var result = helper.helper.apply(root, [null, null, null, hOpts, cOpts]);

            //Assert
            assert.equal(result, config.expected);
            done();
        });

    });

});
<|endoftext|>


<commit_before>var expect = require('chai').expect;
var request = require('supertest');
var bodyParser = require('body-parser');

var conf = require('../../../app/config');
var fixtures = require('../../fixtures/fixtures');

var apiSuffix = conf.get('apiSuffix') + "subscriptions";
console.log(apiSuffix);
var authHeader = {'Authorization': 'Bearer ' + conf.get('apiKey')}

var app = require('../../../app');
app.use(bodyParser.urlencoded({
  extended: true
}));

describe('Subscription routes', function() {
  describe('show', function() {
    it('should show all subscriptions', function() {
      request(app)
        .get(apiSuffix)
        .set(authHeader)
        .end(function(err, res) {
          expect(err).to.equal(null);
          expect(res.statusCode).to.equal(200);
          expect(res.body).to.be.an('array');
          // expect(res.body.length).to.equal(3);
          // expect(res.body[0].email).to.equal('test1@test.com');
        });
    });
  });
});
<commit_msg>Proper test for show all subscriptions<commit_after>var expect = require('chai').expect;
var request = require('supertest');
var bodyParser = require('body-parser');

var conf = require('../../../app/config');
var fixtures = require('../../fixtures/fixtures');

var apiSuffix = conf.get('apiSuffix') + "subscriptions";
console.log(apiSuffix);
var authHeader = {'Authorization': 'Bearer ' + conf.get('apiKey')}

var app = require('../../../app');
app.use(bodyParser.urlencoded({
  extended: true
}));

describe('Subscription routes', function() {
  describe('show', function() {
    it('should show all subscriptions', function() {
      request(app)
        .get(apiSuffix)
        .set(authHeader)
        .end(function(err, res) {
          expect(err).to.equal(null);
          expect(res.statusCode).to.equal(200);
          expect(res.body).to.be.an('array');
          expect(res.body.length).to.equal(3);
          expect(res.body[0].shopName).to.equal('UnicornFluff');
        });
    });
  });
});
<|endoftext|>


<commit_before>import Moment from "moment";
import React from "react";
import styled from "styled-components";
import { Box, ExternalLink, Flex, FlexItem, Icon, Loader, RelativeTime } from "../../../base";

const ridRoot =
    "https://blast.ncbi.nlm.nih.gov/Blast.cgi?\
    CMD=Web&PAGE_TYPE=BlastFormatting&OLD_BLAST=false&GET_RID_INFO=on&RID=";

export const RIDLink = ({ rid }) => {
    if (rid) {
        return (

                 with RID
                <ExternalLink href={ridRoot + rid}>
                    {rid}{" "}

                        <Icon name="new-tab" />

                </ExternalLink>

        );
    }

    return null;
};

const StyledRIDTiming = styled.div`
    font-size: 12px;
    margin-left: auto;
`;

export const RIDTiming = ({ interval, lastCheckedAt }) => {
    if (lastCheckedAt) {
        const relativeNext = Moment(lastCheckedAt)
            .add(interval, "seconds")
            .fromNow();

        return (

        );
    }

    return null;
};

const StyledBLASTInProgress = styled(Box)`
    align-items: flex-start;
    display: flex;

    div:first-of-type {
        margin-right: 5px;
    }
`;

export const BLASTInProgress = ({ interval, lastCheckedAt, rid }) => {
    return (

    );
};
<commit_msg>Remove unused import<commit_after>import Moment from "moment";
import React from "react";
import styled from "styled-components";
import { Box, ExternalLink, Icon, Loader, RelativeTime } from "../../../base";

const ridRoot =
    "https://blast.ncbi.nlm.nih.gov/Blast.cgi?\
    CMD=Web&PAGE_TYPE=BlastFormatting&OLD_BLAST=false&GET_RID_INFO=on&RID=";

export const RIDLink = ({ rid }) => {
    if (rid) {
        return (

                 with RID
                <ExternalLink href={ridRoot + rid}>
                    {rid}{" "}

                        <Icon name="new-tab" />

                </ExternalLink>

        );
    }

    return null;
};

const StyledRIDTiming = styled.div`
    font-size: 12px;
    margin-left: auto;
`;

export const RIDTiming = ({ interval, lastCheckedAt }) => {
    if (lastCheckedAt) {
        const relativeNext = Moment(lastCheckedAt)
            .add(interval, "seconds")
            .fromNow();

        return (

        );
    }

    return null;
};

const StyledBLASTInProgress = styled(Box)`
    align-items: flex-start;
    display: flex;

    div:first-of-type {
        margin-right: 5px;
    }
`;

export const BLASTInProgress = ({ interval, lastCheckedAt, rid }) => {
    return (

    );
};
<|endoftext|>


<commit_before>import angular from 'angular';
import {modalModule} from 'common/components/modal';
import {selectModule} from 'common/components/select';
import {futureStateModule} from 'common/utils/lazy-routes';
import './builder.tpl';

export var builderModule = angular.module('admin.builder', [modalModule.name, 'app/admin/builder/builder.tpl.html']);

builderModule.controller('BuilderController', function($scope){
  console.log('builder!')
});
<commit_msg>fix missing import<commit_after>import angular from 'angular';
import {modalModule} from 'common/components/modal';
import {selectModule} from 'common/components/select';
import './builder.tpl';

export var builderModule = angular.module('admin.builder', [modalModule.name, 'app/admin/builder/builder.tpl.html']);

builderModule.controller('BuilderController', function($scope){
  console.log('builder!')
});
<|endoftext|>