<commit_before>define(function (require, exports, module) {

  var currentMedia = require('plug/models/currentMedia'),
    currentRoom = require('plug/models/currentRoom'),
    settings = require('extplug/store/settings'),
    Events = require('plug/core/Events'),
    ApplicationView = require('plug/views/app/ApplicationView'),
    SettingsTabMenuView = require('plug/views/users/settings/TabMenuView'),
    AppSettingsSectionView = require('plug/views/users/settings/SettingsApplicationView'),
    UserView = require('plug/views/users/UserView'),
    UserSettingsView = require('plug/views/users/settings/SettingsView'),
    ChatView = require('plug/views/rooms/chat/ChatView'),
    plugUtil = require('plug/util/util'),
    emoji = require('plug/util/emoji'),

    RoomSettings = require('extplug/models/RoomSettings'),
    ModuleMeta = require('extplug/models/Module'),
    ModulesCollection = require('extplug/collections/ModulesCollection'),
    ExtUserView = require('extplug/views/users/ExtUserView'),
    ExtSettingsSectionView = require('extplug/views/users/settings/SettingsView'),
    ExtSettingsTabMenuView = require('extplug/views/users/settings/TabMenuView'),
    Style = require('extplug/util/Style'),
    fnUtils = require('extplug/util/function'),
    Module = require('extplug/Module'),
    chatFacade = require('extplug/facades/chatFacade'),

    _package = require('extplug/package'),

    $ = require('jquery'),
    _ = require('underscore'),
    Backbone = require('backbone'),
    meld = require('meld');

  var hooks = [
    require('extplug/hooks/api-early'),
    require('extplug/hooks/chat'),
    require('extplug/hooks/playback')
  ];

  /**
   * Gets a reference to the main Plug.DJ ApplicationView instance.
   *
   * The ApplicationView is not stored anywhere public, it just
   * exists as a variable in a require() closure, where we cannot
   * directly retrieve it.
   * However, it adds some events to the global Events channel on render,
   * one of them being "show:room", so that's where we can find a reference.
   *
   * @return {ApplicationView} The ApplicationView instance of this page.
   */
  function getApplicationView() {
    var evts = Events._events['show:room'];
    // Backbone event handlers have a .ctx property, containing what they will be bound to.
    // And ApplicationView adds a handler that's bound to itself!
    var appView
    if (evts) {
      appView = _.find(evts, function (event) { return event.ctx instanceof ApplicationView; })
    }
    return appView && appView.ctx;
  }

  /**
   * Main ExtPlug extension class.
   *
   * This will be instantiated by ExtPlug later, and can then be accessed
   * on `window.ext`.
   *
   * @constructor
   */
  const ExtPlug = Module.extend({
    name: 'ExtPlug',
    settings: {
      corsProxy: { type: 'boolean', default: true, label: 'Use CORS proxy' }
    },
    init() {
      this._super('extplug', this);
      _.extend(this, Backbone.Events);

      /**
       * Internal map of registered modules.
       * @type {Object.<string, Module>}
       */
      this._modules = new ModulesCollection();

      /**
       * jQuery Document object.
       * @type {jQuery|null}
       */
      this.document = null;

      // bound methods
      this.onClick = this.onClick.bind(this);
      this.onVolume = this.onVolume.bind(this);
      this.onJoinedChange = this.onJoinedChange.bind(this);
    },

    /**
     * Checks if a module is enabled.
     *
     * @param {string} name Module name.
     *
     * @return {boolean} True if the Module is enabled, false otherwise.
     */
    enabled(name) {
      var mod = this._modules.findWhere({ name: name });
      return mod ? mod.get('enabled') : false;
    },

    /**
     * Registers a new module.
     *
     * @param {function()} Mod A module constructor created with {@link Module}.
     *
     * @return {ExtPlug} `this`.
     * @deprecated Use registerModule() instead. It integrates better with plug.dj's
     *             require.js-based app, and properly takes care of dependencies.
     */
    register(id, Mod) {
      if (Mod) {
        try {
          var mod = new Mod(id, this);
          this._modules.add(new ModuleMeta({ module: mod, name: mod.name }));
        }
        catch (e) {
          this._modules.add(new ModuleMeta({ module: e, name: mod && mod.name || mod.prototype.name }));
        }
      }
      return this;
    },

    /**
     * Register an ExtPlug module by require.js module name.
     * This can be anything that is accepted by require.js, including
     * modules using require.js plugins or modules on remote URLs.
     */
    registerModule(id) {
      require([ id ], function (Mod) {
        this.register(id, Mod);
      }.bind(this));
      return this;
    },

    /**
     * Initializes ExtPlug.
     *
     * This attaches events and finds some common DOM elements. Also, adds
     * the ExtPlug tab to the user settings area.
     *
     * @return {ExtPlug} `this`.
     */
    enable() {
      this._super();
      var ext = this;

      settings.update();
      this.appView = getApplicationView();

      this.document = $(document);

      this.logo = new Style({
        '#app-menu .button i:after': {
          content: '"EXT"',
          color: '#fff',
          background: '#f00',
          'z-index': 10,
          'font-size': '70%',
          'border-radius': '10px',
          padding: '1px 4px',
          'margin-top': '5px',
          position: 'relative',
          float: 'right'
        }
      });

      this.document.on('click.extplug', this.onClick);

      currentMedia.on('change:volume', this.onVolume);

      const pad = x => x < 10 ? `0${x}` : x
      let ba = new Date(_package.builtAt)
      let builtAt = ba.getUTCFullYear() + '-'
                  + pad(ba.getUTCMonth()   + 1) + '-'
                  + pad(ba.getUTCDate()    + 1) + ' '
                  + pad(ba.getUTCHours()   + 1) + ':'
                  + pad(ba.getUTCMinutes() + 1) + ':'
                  + pad(ba.getUTCSeconds() + 1) + ' UTC'
      chatFacade.registerCommand('version', () => {
        API.chatLog(`${_package.name} v${_package.version} (${builtAt})`);
      });

      // add an ExtPlug settings tab to User Settings
      fnUtils.replaceClass(SettingsTabMenuView, ExtSettingsTabMenuView);
      fnUtils.replaceClass(UserView, ExtUserView);
      // replace rendered UserView
      var userView = new UserView();
      userView.render();
      this.appView.user.$el.replaceWith(userView.$el);
      this.appView.user = userView;

      // add the ExtPlug settings pane
      function addExtPlugSettingsPane(joinpoint) {
        if (joinpoint.args[0] === 'ext-plug') {
          return new ExtSettingsSectionView({ modules: ext._modules, ext: ext });
        }
        return joinpoint.proceed();
      }

      var settingsPaneAdvice = meld.around(UserSettingsView.prototype, 'getView', addExtPlugSettingsPane);
      this.on('deinit', function () { settingsPaneAdvice.remove() });

      // install extra events
      hooks.forEach(function (hook) {
        hook.install();
        this.on('deinit', hook.uninstall);
      }, this);

      // add custom chat message type
      function addCustomChatType(joinpoint) {
        var message = joinpoint.args[0];
        if (message.type.split(' ').indexOf('custom') !== -1) {
          message.type += ' update';
          if (!message.timestamp) {
            message.timestamp = plugUtil.getChatTimestamp();
          }
          joinpoint.proceed();
          if (message.badge) {
            if (/^:(.*?):$/.test(message.badge)) {
              var badgeBox = this.$chatMessages.children().last().find('.badge-box'),
                emojiName = message.badge.slice(1, -1);
              if (emoji.map[emojiName]) {
                badgeBox.find('i').remove();
                badgeBox.append(
                  $('<span />').addClass('emoji-glow extplug-badji').append(
                    $('<span />').addClass('emoji emoji-' + emoji.map[emojiName])
                  )
                );
              }
            }
            else if (/^icon-(.*?)$/.test(message.badge)) {
              var badgeBox = this.$chatMessages.children().last().find('.badge-box')
              badgeBox.find('i')
                .removeClass()
                .addClass('icon').addClass(message.badge);
            }
          }
          if (message.color) {
            this.$chatMessages.children().last().find('.msg .text').css('color', message.color);
          }
        }
        else {
          joinpoint.proceed(message);
        }
      }

      new Style({
        '#chat-messages .cm.inline': {
          '.badge-box': {
            'margin': '5px 8px 6px',
            'height': '17px',
            'border-radius': '0px',
            'background': 'transparent',

            // center badge icons
            '.icon': {
              'top': '50%',
              'margin-top': '-15px'
            }
          },
          '.from': { 'display': 'inline' },
          '.text': { 'display': 'inline', 'margin-left': '5px' }
        },
        '#chat-messages .cm .no-badge .icon': {
          'width': '30px',
          'height': '30px',
          'top': '0px',
          'left': '0px',
          'border': 'none',
          'border-radius': '0px'
        }
      });

      // Replace the event listener too
      var chatView = this.appView.room.chat;
      if (chatView) {
        Events.off('chat:receive', chatView.onReceived);
      }
      var chatTypeAdvice = meld.around(ChatView.prototype, 'onReceived', addCustomChatType);
      this.on('deinit', function () { chatTypeAdvice.remove(); });
      if (chatView) {
        Events.on('chat:receive', chatView.onReceived, chatView);
      }

      // room settings
      var roomSettings = new RoomSettings(this);
      this.roomSettings = roomSettings;
      this.on('deinit', function () {
        roomSettings.dispose();
      });

      currentRoom.on('change:joined', this.onJoinedChange);

      this._loadEnabledModules();

      Events.trigger('notify', 'icon-plug-dj', 'ExtPlug loaded');

      return this;
    },

    /**
     * Deinitializes and cleans up ExtPlug.
     *
     * Everything should be unloaded here, so the Plug.DJ page is like nothing ever happened.
     */
    disable() {
      this._modules.forEach(mod => {
        mod.disable();
      });
      this.trigger('deinit');
      this._super();
    },

    /**
     * Persists enabled modules to localStorage.
     * @private
     */
    _updateEnabledModules() {
      var modules = {};
      this._modules.forEach(function (m) {
        modules[m.get('name')] = {
          enabled: m.get('enabled'),
          settings: m.get('module').settings
        };
      }, this);
      localStorage.setItem('extPlugModules', JSON.stringify(modules));
    },

    /**
     * Enables modules and loads their settings from localStorage.
     * @private
     */
    _loadEnabledModules() {
      var enabled = localStorage.getItem('extPlugModules');
      if (enabled) {
        var modules = JSON.parse(enabled);
        _.each(modules, (m, name) => {
          var mod = this._modules.findWhere({ name: name });
          if (mod) {
            if (m.enabled) {
              mod.enable();
              this._updateEnabledModules();
            }
            mod.get('module').settings.set(m.settings);
          }
        });
      }
    },

    /**
     * Full-page onclick handler.
     *
     * @param {MouseEvent} e Event.
     *
     * @private
     */
    onClick(e) {
      var target = $(e.target);
      if (target.parents('#user-settings').length === 1) {
        settings.update();
      }
    },

    /**
     * Volume change handler.
     *
     * @private
     */
    onVolume() {
      var newVolume = API.getVolume();
      if (settings.get('volume') !== newVolume) {
        settings.set('volume', newVolume);
      }
    },

    /**
     * Room join/leave handler.
     *
     * @private
     */
    onJoinedChange() {
      if (currentRoom.get('joined')) {
        this.trigger('room:joined', currentRoom);
      }
      else {
        this.trigger('room:left', currentRoom);
      }
    },

    /**
     * 3rd party modules should use `extp.push` to register callbacks or modules
     * for when ExtPlug is loaded.
     * This ensures that modules that are loaded *after* ExtPlug will also register.
     *
     * @param {function()} cb
     */
    push(cb) {
      if (typeof cb === 'string') {
        this.registerModule(cb);
      }
      else {
        cb(this);
      }
    }
  });

  module.exports = ExtPlug;

});
<commit_msg>remove most traces of ExtPlug in disable() hook<commit_after>define(function (require, exports, module) {

  var currentMedia = require('plug/models/currentMedia'),
    currentRoom = require('plug/models/currentRoom'),
    settings = require('extplug/store/settings'),
    Events = require('plug/core/Events'),
    ApplicationView = require('plug/views/app/ApplicationView'),
    SettingsTabMenuView = require('plug/views/users/settings/TabMenuView'),
    AppSettingsSectionView = require('plug/views/users/settings/SettingsApplicationView'),
    UserView = require('plug/views/users/UserView'),
    UserSettingsView = require('plug/views/users/settings/SettingsView'),
    ChatView = require('plug/views/rooms/chat/ChatView'),
    plugUtil = require('plug/util/util'),
    emoji = require('plug/util/emoji'),

    RoomSettings = require('extplug/models/RoomSettings'),
    ModuleMeta = require('extplug/models/Module'),
    ModulesCollection = require('extplug/collections/ModulesCollection'),
    ExtUserView = require('extplug/views/users/ExtUserView'),
    ExtSettingsSectionView = require('extplug/views/users/settings/SettingsView'),
    ExtSettingsTabMenuView = require('extplug/views/users/settings/TabMenuView'),
    Style = require('extplug/util/Style'),
    fnUtils = require('extplug/util/function'),
    Module = require('extplug/Module'),
    chatFacade = require('extplug/facades/chatFacade'),

    _package = require('extplug/package'),

    $ = require('jquery'),
    _ = require('underscore'),
    Backbone = require('backbone'),
    meld = require('meld');

  var hooks = [
    require('extplug/hooks/api-early'),
    require('extplug/hooks/chat'),
    require('extplug/hooks/playback')
  ];

  /**
   * Gets a reference to the main Plug.DJ ApplicationView instance.
   *
   * The ApplicationView is not stored anywhere public, it just
   * exists as a variable in a require() closure, where we cannot
   * directly retrieve it.
   * However, it adds some events to the global Events channel on render,
   * one of them being "show:room", so that's where we can find a reference.
   *
   * @return {ApplicationView} The ApplicationView instance of this page.
   */
  function getApplicationView() {
    var evts = Events._events['show:room'];
    // Backbone event handlers have a .ctx property, containing what they will be bound to.
    // And ApplicationView adds a handler that's bound to itself!
    var appView
    if (evts) {
      appView = _.find(evts, function (event) { return event.ctx instanceof ApplicationView; })
    }
    return appView && appView.ctx;
  }

  /**
   * Main ExtPlug extension class.
   *
   * This will be instantiated by ExtPlug later, and can then be accessed
   * on `window.ext`.
   *
   * @constructor
   */
  const ExtPlug = Module.extend({
    name: 'ExtPlug',
    settings: {
      corsProxy: { type: 'boolean', default: true, label: 'Use CORS proxy' }
    },
    init() {
      this._super('extplug', this);
      _.extend(this, Backbone.Events);

      /**
       * Internal map of registered modules.
       * @type {Object.<string, Module>}
       */
      this._modules = new ModulesCollection();

      /**
       * jQuery Document object.
       * @type {jQuery|null}
       */
      this.document = null;

      // bound methods
      this.onClick = this.onClick.bind(this);
      this.onVolume = this.onVolume.bind(this);
      this.onJoinedChange = this.onJoinedChange.bind(this);
    },

    /**
     * Checks if a module is enabled.
     *
     * @param {string} name Module name.
     *
     * @return {boolean} True if the Module is enabled, false otherwise.
     */
    enabled(name) {
      var mod = this._modules.findWhere({ name: name });
      return mod ? mod.get('enabled') : false;
    },

    /**
     * Registers a new module.
     *
     * @param {function()} Mod A module constructor created with {@link Module}.
     *
     * @return {ExtPlug} `this`.
     * @deprecated Use registerModule() instead. It integrates better with plug.dj's
     *             require.js-based app, and properly takes care of dependencies.
     */
    register(id, Mod) {
      if (Mod) {
        try {
          var mod = new Mod(id, this);
          this._modules.add(new ModuleMeta({ module: mod, name: mod.name }));
        }
        catch (e) {
          this._modules.add(new ModuleMeta({ module: e, name: mod && mod.name || mod.prototype.name }));
        }
      }
      return this;
    },

    /**
     * Register an ExtPlug module by require.js module name.
     * This can be anything that is accepted by require.js, including
     * modules using require.js plugins or modules on remote URLs.
     */
    registerModule(id) {
      require([ id ], function (Mod) {
        this.register(id, Mod);
      }.bind(this));
      return this;
    },

    /**
     * Initializes ExtPlug.
     *
     * This attaches events and finds some common DOM elements. Also, adds
     * the ExtPlug tab to the user settings area.
     *
     * @return {ExtPlug} `this`.
     */
    enable() {
      this._super();
      var ext = this;

      settings.update();
      this.appView = getApplicationView();

      this.document = $(document);

      this.Style({
        '#app-menu .button i:after': {
          content: '"EXT"',
          color: '#fff',
          background: '#f00',
          'z-index': 10,
          'font-size': '70%',
          'border-radius': '10px',
          padding: '1px 4px',
          'margin-top': '5px',
          position: 'relative',
          float: 'right'
        }
      });

      const pad = x => x < 10 ? `0${x}` : x
      let ba = new Date(_package.builtAt)
      let builtAt = ba.getUTCFullYear() + '-'
                  + pad(ba.getUTCMonth()   + 1) + '-'
                  + pad(ba.getUTCDate()    + 1) + ' '
                  + pad(ba.getUTCHours()   + 1) + ':'
                  + pad(ba.getUTCMinutes() + 1) + ':'
                  + pad(ba.getUTCSeconds() + 1) + ' UTC'
      chatFacade.registerCommand('version', () => {
        API.chatLog(`${_package.name} v${_package.version} (${builtAt})`);
      });

      // replace rendered UserView
      var userView = new ExtUserView();
      userView.render();
      this.appView.user.$el.replaceWith(userView.$el);
      this.appView.user = userView;

      // Add ExtPlug tab to user settings
      this._settingsTabAdvice = meld.around(UserSettingsView.prototype, 'getMenu', () => {
        return new ExtSettingsTabMenuView();
      });
      this._settingsPaneAdvice = meld.around(UserSettingsView.prototype, 'getView', joinpoint => {
        if (joinpoint.args[0] === 'ext-plug') {
          return new ExtSettingsSectionView({
            modules: ext._modules,
            ext: ext
          });
        }
        return joinpoint.proceed();
      });

      // install extra events
      hooks.forEach(hook => {
        hook.install();
      });

      // add custom chat message type
      function addCustomChatType(joinpoint) {
        var message = joinpoint.args[0];
        if (message.type.split(' ').indexOf('custom') !== -1) {
          message.type += ' update';
          if (!message.timestamp) {
            message.timestamp = plugUtil.getChatTimestamp();
          }
          joinpoint.proceed();
          if (message.badge) {
            if (/^:(.*?):$/.test(message.badge)) {
              var badgeBox = this.$chatMessages.children().last().find('.badge-box'),
                emojiName = message.badge.slice(1, -1);
              if (emoji.map[emojiName]) {
                badgeBox.find('i').remove();
                badgeBox.append(
                  $('<span />').addClass('emoji-glow extplug-badji').append(
                    $('<span />').addClass('emoji emoji-' + emoji.map[emojiName])
                  )
                );
              }
            }
            else if (/^icon-(.*?)$/.test(message.badge)) {
              var badgeBox = this.$chatMessages.children().last().find('.badge-box')
              badgeBox.find('i')
                .removeClass()
                .addClass('icon').addClass(message.badge);
            }
          }
          if (message.color) {
            this.$chatMessages.children().last().find('.msg .text').css('color', message.color);
          }
        }
        else {
          joinpoint.proceed(message);
        }
      }

      this.Style({
        '#chat-messages .cm.inline': {
          '.badge-box': {
            'margin': '5px 8px 6px',
            'height': '17px',
            'border-radius': '0px',
            'background': 'transparent',

            // center badge icons
            '.icon': {
              'top': '50%',
              'margin-top': '-15px'
            }
          },
          '.from': { 'display': 'inline' },
          '.text': { 'display': 'inline', 'margin-left': '5px' }
        },
        '#chat-messages .cm .no-badge .icon': {
          'width': '30px',
          'height': '30px',
          'top': '0px',
          'left': '0px',
          'border': 'none',
          'border-radius': '0px'
        }
      });

      // Replace the event listener too
      var chatView = this.appView.room.chat;
      if (chatView) {
        Events.off('chat:receive', chatView.onReceived);
      }
      this._chatTypeAdvice = meld.around(ChatView.prototype, 'onReceived', addCustomChatType);
      if (chatView) {
        Events.on('chat:receive', chatView.onReceived, chatView);
      }

      // room settings
      this.roomSettings = new RoomSettings(this);

      this.document.on('click.extplug', this.onClick);
      currentMedia.on('change:volume', this.onVolume);
      currentRoom.on('change:joined', this.onJoinedChange);

      this._loadEnabledModules();

      Events.trigger('notify', 'icon-plug-dj', 'ExtPlug loaded');

      return this;
    },

    /**
     * Deinitializes and cleans up ExtPlug.
     *
     * Everything should be unloaded here, so the Plug.DJ page looks like nothing ever happened.
     */
    disable() {
      this._modules.forEach(mod => {
        mod.disable();
      });
      hooks.forEach(hook => {
        hook.uninstall();
      });
      // remove settings pane
      this._settingsTabAdvice.remove();
      this._settingsPaneAdvice.remove();
      var userView = new UserView();
      userView.render();
      this.appView.user.$el.replaceWith(userView.$el);
      this.appView.user = userView;
      // remove custom chat type advice, and restore
      // the original event listener
      let chatView = this.appView.room.chat;
      if (chatView) Events.off('chat:receive', chatView.onReceived);
      this._chatTypeAdvice.remove();
      if (chatView) Events.on('chat:receive', chatView.onReceived, chatView);

      // remove room settings handling
      this.roomSettings.dispose();
      // remove events
      this.document.off('.extplug');
      currentMedia.off('change:volume', this.onVolume);
      currentRoom.off('change:joined', this.onJoinedChange);
      this.trigger('deinit');
      this._super();
    },

    /**
     * Persists enabled modules to localStorage.
     * @private
     */
    _updateEnabledModules() {
      var modules = {};
      this._modules.forEach(function (m) {
        modules[m.get('name')] = {
          enabled: m.get('enabled'),
          settings: m.get('module').settings
        };
      }, this);
      localStorage.setItem('extPlugModules', JSON.stringify(modules));
    },

    /**
     * Enables modules and loads their settings from localStorage.
     * @private
     */
    _loadEnabledModules() {
      var enabled = localStorage.getItem('extPlugModules');
      if (enabled) {
        var modules = JSON.parse(enabled);
        _.each(modules, (m, name) => {
          var mod = this._modules.findWhere({ name: name });
          if (mod) {
            if (m.enabled) {
              mod.enable();
              this._updateEnabledModules();
            }
            mod.get('module').settings.set(m.settings);
          }
        });
      }
    },

    /**
     * Full-page onclick handler.
     *
     * @param {MouseEvent} e Event.
     *
     * @private
     */
    onClick(e) {
      var target = $(e.target);
      if (target.parents('#user-settings').length === 1) {
        settings.update();
      }
    },

    /**
     * Volume change handler.
     *
     * @private
     */
    onVolume() {
      var newVolume = API.getVolume();
      if (settings.get('volume') !== newVolume) {
        settings.set('volume', newVolume);
      }
    },

    /**
     * Room join/leave handler.
     *
     * @private
     */
    onJoinedChange() {
      if (currentRoom.get('joined')) {
        this.trigger('room:joined', currentRoom);
      }
      else {
        this.trigger('room:left', currentRoom);
      }
    },

    /**
     * 3rd party modules should use `extp.push` to register callbacks or modules
     * for when ExtPlug is loaded.
     * This ensures that modules that are loaded *after* ExtPlug will also register.
     *
     * @param {function()} cb
     */
    push(cb) {
      if (typeof cb === 'string') {
        this.registerModule(cb);
      }
      else {
        cb(this);
      }
    }
  });

  module.exports = ExtPlug;

});
<|endoftext|>


<commit_before>'use strict';
var tinject = require('../lib');
tinject([{
    dstPort: 27017,
    host: 'tunneltest1.com',
    username: 'root'
}, {
    dstPort: 27017,
    host: 'tunneltest2.com',
    username: 'root'
}]);

function create(target) {
    return function runsrv() {
        var srv = require('mongojs')(target);
        srv.forms.findOne({}, function() {
            srv.close();
        });
        srv.on('close', runsrv);
    }
}
create('tunneltest2.com/fc24')();

create('tunneltest1.com/fc24')();
<commit_msg>Improve example.<commit_after>'use strict';

var tinject = require('../lib');

tinject([{
    dstPort: 27017,
    host: 'tunneltest1.com',
    username: 'root'
}, {
    dstPort: 27017,
    host: 'tunneltest2.com',
    username: 'root'
}]);

var srv = require('mongojs')('tunneltest1.com/somedb');
srv.forms.findOne({}, function() {
    srv.close();
});

var srv2 = require('mongojs')('tunneltest2.com/somedb');
srv2.someCollection.findOne({}, function() {
    srv2.close();
});
<|endoftext|>


<commit_before>class __ {
    /**
     * Determines if a reference is a `Number`.
     *
     * @returns {Boolean}
     */
    isNumber(input) {
        return 'number' === typeof input;
    }

    /**
     * Determines if a reference is a `Function`.
     *
     * @returns {Boolean}
     */
    isFunction(input) {
        return 'function' === typeof input;
    }

    /**
     * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
     * considered to be objects. Note: that JavaScript arrays are objects.
     *
     * @see http://jsperf.com/isobject4
     * @returns {Boolean}
     */
    isObject(input) {
        return input && 'object' === typeof input && !Array.isArray(input) && null !== input;
    }

    /**
     * Determines if a reference is defined.
     *
     * @returns {Boolean}
     */
    isDefined(input) {
        return 'undefined' !== typeof input;
    }

    /**
     * Determines if a reference is undefined.
     *
     * @returns {Boolean}
     */
    isDefined(input) {
        return 'undefined' !== typeof input;
    }

    /**
     * Determines if a value is a null object.
     *
     * @returns {Boolean}
     */
    isNull(input) {
        return input === null;
    }

    /**
     * Determines if a value is a array.
     *
     * @returns {Boolean}
     */
    isArray(expectedArray) {
        return Array.isArray(expectedArray);
    }

    /**
     * Determines if a value is a boolean.
     *
     * @returns {Boolean}
     */
    isBoolean(input) {
        return 'boolean' === typeof input;
    }

    /**
     * Determines if a value is a string.
     *
     * @returns {Boolean}
     */
    isString(input) {
        return 'string' === typeof input;
    }

    /**
     * Determines if a value is a element.
     *
     * @returns {Boolean}
     */
    isElement(el) {
        try {
            return el instanceof HTMLElement;
        }
        catch (e) {
            return (this.isObject(el)) &&
                (el.nodeType === 1) && (this.isObject(el.style)) &&
                (this.isObject(el.ownerDocument));
        }
    }

    /**
     * Deep merges unlimited numbers of Objects
     *
     * @param {Object} target
     * @param {Object} source
     * @returns {Object}
     */
    merge(target, source) {
        // _mergeRecursive does the actual job with two arguments.
        let _mergeRecursive = (dst, src) => {
            if (!this.isObject(src) || this.isNull(src)) {
                return dst;
            }

            for (let p in src) {
                if (!src.hasOwnProperty(p) || !this.isDefined(src[p])) continue;

                if (!this.isObject(src[p]) || this.isNull(src[p])) {
                    dst[p] = src[p];
                } else
                if (!this.isObject(dst[p]) || this.isNull(dst[p])) {
                    dst[p] = _mergeRecursive(this.isArray(src[p].constructor) ? [] : {}, src[p]);
                } else {
                    _mergeRecursive(dst[p], src[p]);
                }
            }

            return dst;
        }

        // Loop through arguments and merge them into the first argument.
        let out = arguments[0];
        if (!this.isObject(out) || this.isNull(out)) return out;

        for (let i=1, len = arguments.length; i < len; i++) {
            _mergeRecursive(out, arguments[i]);
        }

        return out;
    }

    /**
     * Determines if the user enter the browser in full screen mode.
     *
     * @returns {Boolean}
     */
    isFullScreen() {
        return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement;
    }
}

export default new __();<commit_msg>timeformat added<commit_after>class __ {
    /**
     * Determines if a reference is a `Number`.
     *
     * @returns {Boolean}
     */
    isNumber(input) {
        return 'number' === typeof input;
    }

    /**
     * Determines if a reference is a `Function`.
     *
     * @returns {Boolean}
     */
    isFunction(input) {
        return 'function' === typeof input;
    }

    /**
     * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
     * considered to be objects. Note: that JavaScript arrays are objects.
     *
     * @see http://jsperf.com/isobject4
     * @returns {Boolean}
     */
    isObject(input) {
        return input && 'object' === typeof input && !Array.isArray(input) && null !== input;
    }

    /**
     * Determines if a reference is defined.
     *
     * @returns {Boolean}
     */
    isDefined(input) {
        return 'undefined' !== typeof input;
    }

    /**
     * Determines if a reference is undefined.
     *
     * @returns {Boolean}
     */
    isDefined(input) {
        return 'undefined' !== typeof input;
    }

    /**
     * Determines if a value is a null object.
     *
     * @returns {Boolean}
     */
    isNull(input) {
        return input === null;
    }

    /**
     * Determines if a value is a array.
     *
     * @returns {Boolean}
     */
    isArray(expectedArray) {
        return Array.isArray(expectedArray);
    }

    /**
     * Determines if a value is a boolean.
     *
     * @returns {Boolean}
     */
    isBoolean(input) {
        return 'boolean' === typeof input;
    }

    /**
     * Determines if a value is a string.
     *
     * @returns {Boolean}
     */
    isString(input) {
        return 'string' === typeof input;
    }

    /**
     * Determines if a value is a element.
     *
     * @returns {Boolean}
     */
    isElement(el) {
        try {
            return el instanceof HTMLElement;
        }
        catch (e) {
            return (this.isObject(el)) &&
                (el.nodeType === 1) && (this.isObject(el.style)) &&
                (this.isObject(el.ownerDocument));
        }
    }

    /**
     * Deep merges unlimited numbers of Objects
     *
     * @param {Object} target
     * @param {Object} source
     * @returns {Object}
     */
    merge(target, source) {
        // _mergeRecursive does the actual job with two arguments.
        let _mergeRecursive = (dst, src) => {
            if (!this.isObject(src) || this.isNull(src)) {
                return dst;
            }

            for (let p in src) {
                if (!src.hasOwnProperty(p) || !this.isDefined(src[p])) continue;

                if (!this.isObject(src[p]) || this.isNull(src[p])) {
                    dst[p] = src[p];
                } else
                if (!this.isObject(dst[p]) || this.isNull(dst[p])) {
                    dst[p] = _mergeRecursive(this.isArray(src[p].constructor) ? [] : {}, src[p]);
                } else {
                    _mergeRecursive(dst[p], src[p]);
                }
            }

            return dst;
        }

        // Loop through arguments and merge them into the first argument.
        let out = arguments[0];
        if (!this.isObject(out) || this.isNull(out)) return out;

        for (let i=1, len = arguments.length; i < len; i++) {
            _mergeRecursive(out, arguments[i]);
        }

        return out;
    }

    /**
     * Determines if the user enter the browser in full screen mode.
     *
     * @returns {Boolean}
     */
    isFullScreen() {
        return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement;
    }

    /**
     *
     */
    formatTime(sec) {
        sec = Math.round(sec);

        let minutes = Math.floor(sec / 60),
            seconds = sec - (minutes * 60);

        seconds = seconds < 10 ? '0' + seconds : seconds;

        return minutes + ':' + seconds;
    }
}

export default new __();<|endoftext|>


<commit_before>
function init() {
    var map = L.map('map', {
        center: [52.0, -11.0],
        zoom: 5,
        layers: [
            L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
                attribution: '© OpenStreetMap contributors'
            })
        ]
    });

    // --- Arrow, with animation to demonstrate the use of setPatterns ---
    var arrow = L.polyline([[57, -19], [60, -12]], {}).addTo(map);
    var arrowHead = L.polylineDecorator(arrow).addTo(map);

    var arrowOffset = 0;
    var anim = window.setInterval(function() {
        arrowHead.setPatterns([
            {offset: arrowOffset+'%', repeat: 0, symbol: L.Symbol.arrowHead({pixelSize: 15, polygon: false, pathOptions: {stroke: true}})}
        ])
        if(++arrowOffset > 100)
            arrowOffset = 0;
    }, 100);

    // --- Polygon, with an inner ring ---
    var polygon = L.polygon([[[54, -6], [55, -7], [56, -2], [55, 1], [53, 0]], [[54, -3], [54, -2], [55, -1], [55, -5]]], {color: "#ff7800", weight: 1}).addTo(map);
    var pd = L.polylineDecorator(polygon, {
        patterns: [
            {offset: 0, repeat: 10, symbol: L.Symbol.dash({pixelSize: 0})}
        ]
    }).addTo(map);

    // --- Multi-pattern without Polyline ---
    var pathPattern = L.polylineDecorator(
        [ [ 49.543519, -12.469833 ], [ 49.808981, -12.895285 ], [ 50.056511, -13.555761 ], [ 50.217431, -14.758789 ], [ 50.476537, -15.226512 ], [ 50.377111, -15.706069 ], [ 50.200275, -16.000263 ], [ 49.860606, -15.414253 ], [ 49.672607, -15.710152 ], [ 49.863344, -16.451037 ], [ 49.774564, -16.875042 ], [ 49.498612, -17.106036 ], [ 49.435619, -17.953064 ], [ 49.041792, -19.118781 ], [ 48.548541, -20.496888 ], [ 47.930749, -22.391501 ], [ 47.547723, -23.781959 ], [ 47.095761, -24.941630 ], [ 46.282478, -25.178463 ], [ 45.409508, -25.601434 ], [ 44.833574, -25.346101 ], [ 44.039720, -24.988345 ] ],
        {
            patterns: [
                { offset: 12, repeat: 25, symbol: L.Symbol.dash({pixelSize: 10, pathOptions: {color: '#f00', weight: 2}}) },
                { offset: 0, repeat: 25, symbol: L.Symbol.dash({pixelSize: 0}) }
            ]
        }
    ).addTo(map);

    // --- Markers proportionnaly located ---
    var markerLine = L.polyline([[58.44773, -28.65234], [52.9354, -23.33496], [53.01478, -14.32617], [58.1707, -10.37109], [59.68993, -0.65918]], {}).addTo(map);
    var markerPatterns = L.polylineDecorator(markerLine, {
        patterns: [
            { offset: '5%', repeat: '10%', symbol: L.Symbol.marker()}
        ]
    }).addTo(map);

    // --- Example with a rotated marker ---
    var pathPattern = L.polylineDecorator(
        [ [ 42.9, -15 ], [ 44.18, -11.4 ], [ 45.77, -8.0 ], [ 47.61, -6.4 ], [ 49.41, -6.1 ], [ 51.01, -7.2 ] ],
        {
            patterns: [
                { offset: 0, repeat: 10, symbol: L.Symbol.dash({pixelSize: 5, pathOptions: {color: '#000', weight: 1, opacity: 0.2}}) },
                { offset: '16%', repeat: '33%', symbol: L.Symbol.marker({rotate: true, markerOptions: {
                    icon: L.icon({
                        iconUrl: 'icon_plane.png',
                        iconAnchor: [16, 16]
                    })
                }})}
            ]
        }
    ).addTo(map);

    // --- Example with an array of Polylines ---
    var multiCoords1 = [
        [[47.5468, -0.7910], [48.8068, -0.1318], [49.1242, 1.6699], [49.4966, 3.2958], [51.4266, 2.8564], [51.7542, 2.1093]],
        [[48.0193, -2.8125], [46.3165, -2.8564], [44.9336, -1.0107], [44.5278, 1.5820], [44.8714, 3.7353], [45.8287, 5.1855], [48.1953, 5.1416]],
        [[45.9205, 0.4394], [46.7699, 0.9228], [47.6061, 2.5488], [47.7540, 3.3837]]
    ];
    var plArray = [];
    for(var i=0; i<multiCoords1.length; i++) {
        plArray.push(L.polyline(multiCoords1[i]).addTo(map));
    }
    L.polylineDecorator(multiCoords1, {
        patterns: [
            {offset: 25, repeat: 50, symbol: L.Symbol.arrowHead({pixelSize: 15, pathOptions: {fillOpacity: 1, weight: 0}})}
        ]
    }).addTo(map);
}
<commit_msg>Remove annoying animation from examples<commit_after>
function init() {
    var map = L.map('map', {
        center: [52.0, -11.0],
        zoom: 5,
        layers: [
            L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
                attribution: '© OpenStreetMap contributors'
            })
        ]
    });

    // --- Simple arrow ---
    var arrow = L.polyline([[57, -19], [60, -12]], {}).addTo(map);
    var arrowHead = L.polylineDecorator(arrow, {
        patterns: [
            {offset: '100%', repeat: 0, symbol: L.Symbol.arrowHead({pixelSize: 15, polygon: false, pathOptions: {stroke: true}})}
        ]
    }).addTo(map);

    // --- Polygon, with an inner ring ---
    var polygon = L.polygon([[[54, -6], [55, -7], [56, -2], [55, 1], [53, 0]], [[54, -3], [54, -2], [55, -1], [55, -5]]], {color: "#ff7800", weight: 1}).addTo(map);
    var pd = L.polylineDecorator(polygon, {
        patterns: [
            {offset: 0, repeat: 10, symbol: L.Symbol.dash({pixelSize: 0})}
        ]
    }).addTo(map);

    // --- Multi-pattern without Polyline ---
    var pathPattern = L.polylineDecorator(
        [ [ 49.543519, -12.469833 ], [ 49.808981, -12.895285 ], [ 50.056511, -13.555761 ], [ 50.217431, -14.758789 ], [ 50.476537, -15.226512 ], [ 50.377111, -15.706069 ], [ 50.200275, -16.000263 ], [ 49.860606, -15.414253 ], [ 49.672607, -15.710152 ], [ 49.863344, -16.451037 ], [ 49.774564, -16.875042 ], [ 49.498612, -17.106036 ], [ 49.435619, -17.953064 ], [ 49.041792, -19.118781 ], [ 48.548541, -20.496888 ], [ 47.930749, -22.391501 ], [ 47.547723, -23.781959 ], [ 47.095761, -24.941630 ], [ 46.282478, -25.178463 ], [ 45.409508, -25.601434 ], [ 44.833574, -25.346101 ], [ 44.039720, -24.988345 ] ],
        {
            patterns: [
                { offset: 12, repeat: 25, symbol: L.Symbol.dash({pixelSize: 10, pathOptions: {color: '#f00', weight: 2}}) },
                { offset: 0, repeat: 25, symbol: L.Symbol.dash({pixelSize: 0}) }
            ]
        }
    ).addTo(map);

    // --- Markers proportionnaly located ---
    var markerLine = L.polyline([[58.44773, -28.65234], [52.9354, -23.33496], [53.01478, -14.32617], [58.1707, -10.37109], [59.68993, -0.65918]], {}).addTo(map);
    var markerPatterns = L.polylineDecorator(markerLine, {
        patterns: [
            { offset: '5%', repeat: '10%', symbol: L.Symbol.marker()}
        ]
    }).addTo(map);

    // --- Example with a rotated marker ---
    var pathPattern = L.polylineDecorator(
        [ [ 42.9, -15 ], [ 44.18, -11.4 ], [ 45.77, -8.0 ], [ 47.61, -6.4 ], [ 49.41, -6.1 ], [ 51.01, -7.2 ] ],
        {
            patterns: [
                { offset: 0, repeat: 10, symbol: L.Symbol.dash({pixelSize: 5, pathOptions: {color: '#000', weight: 1, opacity: 0.2}}) },
                { offset: '16%', repeat: '33%', symbol: L.Symbol.marker({rotate: true, markerOptions: {
                    icon: L.icon({
                        iconUrl: 'icon_plane.png',
                        iconAnchor: [16, 16]
                    })
                }})}
            ]
        }
    ).addTo(map);

    // --- Example with an array of Polylines ---
    var multiCoords1 = [
        [[47.5468, -0.7910], [48.8068, -0.1318], [49.1242, 1.6699], [49.4966, 3.2958], [51.4266, 2.8564], [51.7542, 2.1093]],
        [[48.0193, -2.8125], [46.3165, -2.8564], [44.9336, -1.0107], [44.5278, 1.5820], [44.8714, 3.7353], [45.8287, 5.1855], [48.1953, 5.1416]],
        [[45.9205, 0.4394], [46.7699, 0.9228], [47.6061, 2.5488], [47.7540, 3.3837]]
    ];
    var plArray = [];
    for(var i=0; i<multiCoords1.length; i++) {
        plArray.push(L.polyline(multiCoords1[i]).addTo(map));
    }
    L.polylineDecorator(multiCoords1, {
        patterns: [
            {offset: 25, repeat: 50, symbol: L.Symbol.arrowHead({pixelSize: 15, pathOptions: {fillOpacity: 1, weight: 0}})}
        ]
    }).addTo(map);
}
<|endoftext|>


<commit_before>'use strict';

var React = require('react');
var Spreadsheet = require('../src/filepicker');

var config = {
    showFiletypeIcon: false
};

// Render
React.render(<Filepicker config={config} />, document.getElementById('content'));
<commit_msg>Filetypes in Config<commit_after>'use strict';

var React = require('react');
var Spreadsheet = require('../src/filepicker');

var config = {
    allowedFiletypes: ['jpg', 'png', 'gif'],
    showFiletypeIcon: false
};

// Render
React.render(<Filepicker config={config} />, document.getElementById('content'));
<|endoftext|>


<commit_before>/* =============================================================

    Buoy v1.0
    A simple vanilla JS micro-library by Chris Ferdinandi.
    http://gomakethings.com

    Class handlers by Todd Motto.
    http://toddmotto.com/

    Module pattern by Keith Rousseau.
    https://twitter.com/keithtri

    Free to use under the MIT License.
    http://gomakethings.com/mit/

 * ============================================================= */

window.buoy = (function(){

    // Check if an element has a class
    var hasClass = function (elem, className) {
        return new RegExp(' ' + className + ' ').test(' ' + elem.className + ' ');
    }

    // Add a class to an element
    var addClass = function (elem, className) {
        if (!hasClass(elem, className)) {
            elem.className += ' ' + className;
        }
    }

    // Remove a class from an element
    var removeClass = function (elem, className) {
        var newClass = ' ' + elem.className.replace( /[\t\r\n]/g, ' ') + ' ';
        if (hasClass(elem, className)) {
            while (newClass.indexOf(' ' + className + ' ') >= 0 ) {
                newClass = newClass.replace(' ' + className + ' ', ' ');
            }
            elem.className = newClass.replace(/^\s+|\s+$/g, '');
        }
    }

    // Toggle a class on an element
    var toggleClass = function (elem, className) {
        if ( hasClass(elem, className) ) {
            removeClass(elem, className);
        }
        else {
            addClass(elem, className);
        }
    }

    // Get siblings of an element
    var getSiblings = function (elem) {
        var siblings = [];
        var sibling = elem.parentNode.firstChild;
        var skipMe = elem;
        for ( ; sibling; sibling = sibling.nextSibling )
           if ( sibling.nodeType == 1 && sibling != elem )
              siblings.push( sibling );
        return siblings;
    }

    // Return functions
    return{
        toggleClass: toggleClass,
        removeClass: removeClass,
        addClass: addClass,
        hasClass: hasClass,
        getSiblings: getSiblings
    };

})();
<commit_msg>Updated Buoy<commit_after>/* =============================================================

    Buoy v1.1
    A simple vanilla JS micro-library by Chris Ferdinandi.
    http://gomakethings.com

    Class handlers by Todd Motto.
    http://toddmotto.com/

    Module pattern by Keith Rousseau.
    https://twitter.com/keithtri

    Free to use under the MIT License.
    http://gomakethings.com/mit/

 * ============================================================= */

window.buoy = (function(){

    // Check if an element has a class
    var hasClass = function (elem, className) {
        return new RegExp(' ' + className + ' ').test(' ' + elem.className + ' ');
    };

    // Add a class to an element
    var addClass = function (elem, className) {
        if (!hasClass(elem, className)) {
            elem.className += ' ' + className;
        }
    };

    // Remove a class from an element
    var removeClass = function (elem, className) {
        var newClass = ' ' + elem.className.replace( /[\t\r\n]/g, ' ') + ' ';
        if (hasClass(elem, className)) {
            while (newClass.indexOf(' ' + className + ' ') >= 0 ) {
                newClass = newClass.replace(' ' + className + ' ', ' ');
            }
            elem.className = newClass.replace(/^\s+|\s+$/g, '');
        }
    };

    // Toggle a class on an element
    var toggleClass = function (elem, className) {
        if ( hasClass(elem, className) ) {
            removeClass(elem, className);
        }
        else {
            addClass(elem, className);
        }
    };

    // Get siblings of an element
    var getSiblings = function (elem) {
        var siblings = [];
        var sibling = elem.parentNode.firstChild;
        var skipMe = elem;
        for ( ; sibling; sibling = sibling.nextSibling )
           if ( sibling.nodeType == 1 && sibling != elem )
              siblings.push( sibling );
        return siblings;
    };

    // Return functions
    return{
        toggleClass: toggleClass,
        removeClass: removeClass,
        addClass: addClass,
        hasClass: hasClass,
        getSiblings: getSiblings
    };

})();<|endoftext|>


<commit_before>// ----------------------------------------------------------------------------
// buzz - A HTML5 audio library
// v 1.0 alpha
// Dual licensed under the MIT and GPL licenses.
// http://buzz.jaysalvat.com/
// ----------------------------------------------------------------------------
// Copyright (C) 2011 Jay Salvat
// http://jaysalvat.com/
// ----------------------------------------------------------------------------
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files ( the "Software" ), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// ----------------------------------------------------------------------------

var buzz = {
    defaults: {
        preload: 'auto', // auto, metadata, none
        autoplay: false, // bool
        loop: false, // bool
        volume: 100,
        placeholder: '--',
        fadeSpeed: 5000,
        formats: []
    },
    sounds: [],
    el: document.createElement( 'audio' ),
    isSupported: function() {
        return !!( this.el.canPlayType );
    },
    isOGGSupported: function() {
        return !!this.el.canPlayType && this.el.canPlayType( 'audio/ogg; codecs="vorbis"' );
    },
    isWAVSupported: function() {
        return !!this.el.canPlayType && this.el.canPlayType( 'audio/wav; codecs="1"' );
    },
    isMP3Supported: function() {
        return !!this.el.canPlayType && this.el.canPlayType( 'audio/mpeg;' );
    },
    isAACSupported: function() {
        return !!this.el.canPlayType && ( this.el.canPlayType( 'audio/x-m4a;' ) || this.el.canPlayType( 'audio/aac;' ) );
    },
    sound: function( src, options ) {
        var options = options || {},
            pid = 0,
            events = [],
            eventsOnce = {},
            supported = buzz.isSupported();

        this.load = function() {
            if ( !supported ) return this;

            this.sound.load();
            return this;
        }
        this.play = function() {
            if ( !supported ) return this;

            this.sound.play();
            return this;
        }
        this.stop = function() {
            if ( !supported  ) return this;

            this.setTime(0);
            this.sound.pause();
            return this;
        }
        this.isEnded = function() {
            if ( !supported ) return null;

            return this.sound.ended;
        }
        this.pause = function() {
            if ( !supported ) return this;

            this.sound.pause();
            return this;
        }
        this.isPaused = function() {
            if ( !supported ) return null;

            return this.sound.paused;
        }
        this.loop = function() {
            this.sound.loop = true;
            this.bind( 'ended.buzzloop', function() {
                this.currentTime = 0;
                this.play();
            });
        }
        this.unloop = function() {
            this.sound.removeAttribute( 'loop');
            this.unbind( 'ended.buzzloop' );
        }
        this.mute = function() {
            if ( !supported ) return this;

            this.sound.muted = true;
            return this;
        }
        this.unmute = function() {
            if ( !supported ) return this;

            this.sound.muted = false;
            return this;
        }
        this.toggleMute = function() {
            if ( !supported ) return this;

            this.sound.muted = !this.sound.muted;
            return this;
        }
        this.isMuted = function() {
            if ( !supported ) return null;

            return this.sound.muted;
        }
        this.togglePlay = function() {
            if ( !supported ) return this;

            if ( this.sound.paused ) {
                this.sound.play();
            } else {
                this.sound.pause();
            }
            return this;
        }
        this.setVolume = function( volume ) {
            if ( !supported ) return this;

            if ( volume < 0 ) volume = 0;
            if ( volume > 100 ) volume = 100;
            this.volume = volume;
            this.sound.volume = volume / 100;
            return this;
        },
        this.getVolume = function() {
            if ( !supported ) return this;

            return this.volume;
        }
        this.increaseVolume = function( value ) {
            return this.setVolume( this.volume + ( value || 1 ) );
        }
        this.decreaseVolume = function( value ) {
            return this.setVolume( this.volume - ( value || 1 ) );
        }
        this.setTime = function( time ) {
            if ( !supported ) return this;

            var splits = time.toString().split( ':' );
            if ( splits && splits.length == 3 ) {
                time = ( parseInt( splits[0] ) * 3600 ) + ( parseInt(splits[1] ) * 60 ) + parseInt( splits[2] );
            }
            if ( splits && splits.length == 2 ) {
                time = ( parseInt( splits[0] ) * 60 ) + parseInt( splits[1] );
            }

            this.whenReady( function() {
                this.sound.currentTime = time;
            });
            return this;
        }
        this.getTime = function() {
            if ( !supported ) return null;

            var time = Math.round( this.sound.currentTime * 100 ) / 100;
            return isNaN(time) ? buzz.defaults.placeholder : time;
        }
        this.setPercent = function( time ) {
            if ( !supported ) return this;

            return this.setTime( this.sound.duration * time / 100 );
        }
        this.getPercent = function() {
            if ( !supported ) return null;

            var percent = Math.round( ( this.sound.currentTime / this.sound.duration * 100 ) * 100 ) / 100;
            return isNaN(percent) ? buzz.defaults.placeholder : percent;
        }
        this.getDuration = function() {
            if ( !supported ) return null;

            var duration = Math.round( this.sound.duration * 100 ) / 100;
            return isNaN(duration) ? buzz.defaults.placeholder : duration;
        }
        this.set = function( key, value ) {
            if ( !supported ) return this;

            this.sound[ key ] = value;
            return this;
        }
        this.get = function( key ) {
            if ( !supported ) return null;

            return key ? this.sound[ key ] : this.sound;
        }
        this.bind = function( type, func ) {
            if ( !supported ) return this;

            var that = this,
				idx = type;
				type = type.split( '.' )[0],
				efunc = function(e) { func.call(that, e) };

            events.push( { idx: idx, func: efunc } );
            this.sound.addEventListener( type, efunc, true );
            return this;
        }
        this.unbind = function( type ) {
            if ( !supported ) return this;

            var idx = type;
				type = type.split( '.' )[0];

            for( var i in events ) {
                var namespace = events[ i ].idx.split( '.' );
                if ( events[ i ].idx == idx || ( namespace[1] && namespace[1] == idx.replace( '.', '' ) ) ) {
					this.sound.removeEventListener( type, events[ i ].func, true );
                    delete events[ i ];
                }
            }
            return this;
        }
        this.bindOnce = function( type, func ) {
            if ( !supported ) return this;

            var that = this;
            eventsOnce[ pid++ ] = false;
            this.bind( pid + type, function() {
               if ( !eventsOnce[ pid ] ) {
                   eventsOnce[ pid ] = true;
                   func.call( that );
               }
               that.unbind( pid + type );
            });
        }
        this.destroy = function() {
            if ( !supported ) return this;

            for( var i in buzz.sounds ) {
                if ( buzz.sounds[ i ] == this ) {
                    delete buzz.sounds[ i ];
                    break;
                }
            }
            return this;
        }
        this.fadeIn = function( speed, callback ) {
            speed = speed || buzz.defaults.fadeSpeed;
            var delay = speed / 100,
                that = this;
            this.volume = 0;
            this.play();

            function doFade() {
                setTimeout( function() {
                    if ( that.volume < 100 ) {
                        that.setVolume( that.volume += 1 );
                        doFade();
                    } else if ( callback instanceof Function ) {
                        callback.apply( that );
                    }
                }, delay );
            }
            doFade();
        }
        this.fadeOut = function( speed, callback ) {
            speed = speed || buzz.defaults.fadeSpeed;
            var delay = speed / this.volume,
                that = this;

            function doFade() {
                setTimeout( function() {
                    if ( that.volume > 0 ) {
                        that.setVolume( that.volume -= 1 );
                        doFade();
                    } else if ( callback instanceof Function ) {
                        callback.apply( that );
                    }
                }, delay );
            }
            doFade();
        }
        this.fadeWith = function( sound, speed ) {
            this.fadeOut( speed, function() {
                this.stop();
            });
            if ( sound instanceof buzz.sound) {
                sound.play().fadeIn( speed );
            }
        }
        this.whenReady = function( func ) {
            var that = this;
            if ( this.sound.readyState == 0 ) {
                this.bind( 'canplay.buzzwhenready', function() {
                    func.call( that );
                });
            } else {
                func.call( that );
            }
        }

        // init
        if ( supported ) {
            for( var i in buzz.defaults ) {
                options[ i ] = options[ i ] || buzz.defaults[ i ];
            }

            this.sound = document.createElement( 'audio' );
            if ( src instanceof Array ) {
                for( var i in src ) {
                    var source = document.createElement( 'source' );
                    source.src = src[ i ];
                    this.sound.appendChild( source );
                }
            } else if ( options.formats.length ) {
                for( var i in options.formats ) {
                    var source = document.createElement( 'source' );
                    source.src = src + '.' + options.formats[ i ];
                    this.sound.appendChild( source );
                }
            } else {
                this.sound.src = src;
            }
            if ( options.loop ) {
                this.loop();
            }
            if ( options.autoplay ) {
                this.sound.autoplay = 'autoplay';
            }
            this.sound.preload = options.preload;
            this.volume = options.volume;

            buzz.sounds.push( this );
        }
    },
    all: function() {
      return new buzz.group( buzz.sounds );
    },
    group: function( sounds ) {
        fn = function() {
            var args = Array.prototype.slice.call( arguments ),
                func = args.shift();

            for( var i in sounds ) {
                sounds[ i ][ func ].apply( sounds[ i ], args );
            }
        }
        this.play = function() {
            fn( 'play' );
            return this;
        }
        this.stop = function() {
            fn( 'stop' );
            return this;
        }
        this.pause = function( time ) {
            fn( 'pause', time );
            return this;
        }
        this.togglePlay = function( ) {
            fn( 'togglePlay' );
            return this;
        }
        this.mute = function() {
            fn( 'mute' );
            return this;
        }
        this.unmute = function() {
            fn( 'unmute' );
            return this;
        }
        this.toggleMute = function() {
            fn( 'toggleMute' );
            return this;
        }
        this.setVolume = function( volume ) {
            fn( 'setVolume', volume );
            return this;
        }
        this.increaseVolume = function( value ) {
            fn( 'increaseVolume', value );
            return this;
        }
        this.decreaseVolume = function( value ) {
            fn( 'decreaseVolume', value );
            return this;
        }
        this.loop = function() {
            fn( 'loop' );
            return this;
        }
        this.unloop = function() {
            fn( 'unloop' );
            return this;
        }
        this.setTime = function( time ) {
            fn( 'setTime', time );
            return this;
        }
        this.set = function( key, value ) {
            fn( 'set', key, value );
            return this;
        }
        this.bind = function( type, func ) {
            fn( 'bind', type, func );
            return this;
        }
        this.unbind = function( type ) {
            fn( 'unbind', type );
            return this;
        }
        this.destroy = function() {
            fn( 'destroy' );
            return this;
        }
        this.fadeIn = function( speed, callback ) {
            fn( 'fadeIn', speed, callback );
            return this;
        }
        this.fadeOut = function( speed, callback ) {
            fn( 'fadeOut', speed, callback );
            return this;
        }
    },
    formatTime: function( s, withHours ) {
        h = Math.floor( s / 3600 );
        h = isNaN(h) ? '--' : ( h >= 10 ) ? h : '0' + h;
        m = withHours ? Math.floor( s / 60 % 60 ) : Math.floor( s / 60 );
        m = isNaN(m) ? '--' : ( m >= 10 ) ? m : '0' + m;
        s = Math.floor( s % 60 );
        s = isNaN(s) ? '--' : ( s >= 10 ) ? s : '0' + s;
        return withHours ? h + ':' + m + ':' + s : m + ':' + s;
    }
}<commit_msg>Add fade method<commit_after>// ----------------------------------------------------------------------------
// buzz - A HTML5 audio library
// v 1.0 alpha
// Dual licensed under the MIT and GPL licenses.
// http://buzz.jaysalvat.com/
// ----------------------------------------------------------------------------
// Copyright (C) 2011 Jay Salvat
// http://jaysalvat.com/
// ----------------------------------------------------------------------------
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files ( the "Software" ), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// ----------------------------------------------------------------------------

var buzz = {
    defaults: {
        preload: 'auto', // auto, metadata, none
        autoplay: false, // bool
        loop: false, // bool
        volume: 100,
        placeholder: '--',
        fadeSpeed: 5000,
        formats: []
    },
    sounds: [],
    el: document.createElement( 'audio' ),
    isSupported: function() {
        return !!( this.el.canPlayType );
    },
    isOGGSupported: function() {
        return !!this.el.canPlayType && this.el.canPlayType( 'audio/ogg; codecs="vorbis"' );
    },
    isWAVSupported: function() {
        return !!this.el.canPlayType && this.el.canPlayType( 'audio/wav; codecs="1"' );
    },
    isMP3Supported: function() {
        return !!this.el.canPlayType && this.el.canPlayType( 'audio/mpeg;' );
    },
    isAACSupported: function() {
        return !!this.el.canPlayType && ( this.el.canPlayType( 'audio/x-m4a;' ) || this.el.canPlayType( 'audio/aac;' ) );
    },
    sound: function( src, options ) {
        var options = options || {},
            pid = 0,
            events = [],
            eventsOnce = {},
            supported = buzz.isSupported();

        this.load = function() {
            if ( !supported ) return this;

            this.sound.load();
            return this;
        }
        this.play = function() {
            if ( !supported ) return this;

            this.sound.play();
            return this;
        }
        this.stop = function() {
            if ( !supported  ) return this;

            this.setTime(0);
            this.sound.pause();
            return this;
        }
        this.isEnded = function() {
            if ( !supported ) return null;

            return this.sound.ended;
        }
        this.pause = function() {
            if ( !supported ) return this;

            this.sound.pause();
            return this;
        }
        this.isPaused = function() {
            if ( !supported ) return null;

            return this.sound.paused;
        }
        this.loop = function() {
            this.sound.loop = true;
            this.bind( 'ended.buzzloop', function() {
                this.currentTime = 0;
                this.play();
            });
        }
        this.unloop = function() {
            this.sound.removeAttribute( 'loop');
            this.unbind( 'ended.buzzloop' );
        }
        this.mute = function() {
            if ( !supported ) return this;

            this.sound.muted = true;
            return this;
        }
        this.unmute = function() {
            if ( !supported ) return this;

            this.sound.muted = false;
            return this;
        }
        this.toggleMute = function() {
            if ( !supported ) return this;

            this.sound.muted = !this.sound.muted;
            return this;
        }
        this.isMuted = function() {
            if ( !supported ) return null;

            return this.sound.muted;
        }
        this.togglePlay = function() {
            if ( !supported ) return this;

            if ( this.sound.paused ) {
                this.sound.play();
            } else {
                this.sound.pause();
            }
            return this;
        }
        this.setVolume = function( volume ) {
            if ( !supported ) return this;

            if ( volume < 0 ) volume = 0;
            if ( volume > 100 ) volume = 100;
            this.volume = volume;
            this.sound.volume = volume / 100;
            return this;
        },
        this.getVolume = function() {
            if ( !supported ) return this;

            return this.volume;
        }
        this.increaseVolume = function( value ) {
            return this.setVolume( this.volume + ( value || 1 ) );
        }
        this.decreaseVolume = function( value ) {
            return this.setVolume( this.volume - ( value || 1 ) );
        }
        this.setTime = function( time ) {
            if ( !supported ) return this;

            var splits = time.toString().split( ':' );
            if ( splits && splits.length == 3 ) {
                time = ( parseInt( splits[0] ) * 3600 ) + ( parseInt(splits[1] ) * 60 ) + parseInt( splits[2] );
            }
            if ( splits && splits.length == 2 ) {
                time = ( parseInt( splits[0] ) * 60 ) + parseInt( splits[1] );
            }

            this.whenReady( function() {
                this.sound.currentTime = time;
            });
            return this;
        }
        this.getTime = function() {
            if ( !supported ) return null;

            var time = Math.round( this.sound.currentTime * 100 ) / 100;
            return isNaN(time) ? buzz.defaults.placeholder : time;
        }
        this.setPercent = function( time ) {
            if ( !supported ) return this;

            return this.setTime( this.sound.duration * time / 100 );
        }
        this.getPercent = function() {
            if ( !supported ) return null;

            var percent = Math.round( ( this.sound.currentTime / this.sound.duration * 100 ) * 100 ) / 100;
            return isNaN(percent) ? buzz.defaults.placeholder : percent;
        }
        this.getDuration = function() {
            if ( !supported ) return null;

            var duration = Math.round( this.sound.duration * 100 ) / 100;
            return isNaN(duration) ? buzz.defaults.placeholder : duration;
        }
        this.set = function( key, value ) {
            if ( !supported ) return this;

            this.sound[ key ] = value;
            return this;
        }
        this.get = function( key ) {
            if ( !supported ) return null;

            return key ? this.sound[ key ] : this.sound;
        }
        this.bind = function( type, func ) {
            if ( !supported ) return this;

            var that = this,
				idx = type;
				type = type.split( '.' )[0],
				efunc = function(e) { func.call(that, e) };

            events.push( { idx: idx, func: efunc } );
            this.sound.addEventListener( type, efunc, true );
            return this;
        }
        this.unbind = function( type ) {
            if ( !supported ) return this;

            var idx = type;
				type = type.split( '.' )[0];

            for( var i in events ) {
                var namespace = events[ i ].idx.split( '.' );
                if ( events[ i ].idx == idx || ( namespace[1] && namespace[1] == idx.replace( '.', '' ) ) ) {
					this.sound.removeEventListener( type, events[ i ].func, true );
                    delete events[ i ];
                }
            }
            return this;
        }
        this.bindOnce = function( type, func ) {
            if ( !supported ) return this;

            var that = this;
            eventsOnce[ pid++ ] = false;
            this.bind( pid + type, function() {
               if ( !eventsOnce[ pid ] ) {
                   eventsOnce[ pid ] = true;
                   func.call( that );
               }
               that.unbind( pid + type );
            });
        }
        this.destroy = function() {
            if ( !supported ) return this;

            for( var i in buzz.sounds ) {
                if ( buzz.sounds[ i ] == this ) {
                    delete buzz.sounds[ i ];
                    break;
                }
            }
            return this;
        }
        this.fade = function( from, to, speed, callback ) {
            if ( speed instanceof Function ) {
                callback = speed;
                speed = buzz.defaults.fadeSpeed;
            } else {
                speed = speed || buzz.defaults.fadeSpeed;
            }

            var delay = speed / Math.abs( from - to ),
                that = this;
            this.play();
            that.setVolume( from );

            function doFade() {
                setTimeout( function() {
                    if ( from < to && that.volume < to ) {
                        that.setVolume( that.volume += 1 );
                        doFade();
                    } else if ( from > to && that.volume > to ) {
                        that.setVolume( that.volume -= 1 );
                        doFade();
                    } else if ( callback instanceof Function ) {
                        callback.apply( that );
                    }
                }, delay );
            }
            doFade();
        }
        this.fadeIn = function( speed, callback ) {
            speed = speed || buzz.defaults.fadeSpeed;
            var delay = speed / 100,
                that = this;
            this.volume = 0;
            this.play();

            function doFade() {
                setTimeout( function() {
                    if ( that.volume < 100 ) {
                        that.setVolume( that.volume += 1 );
                        doFade();
                    } else if ( callback instanceof Function ) {
                        callback.apply( that );
                    }
                }, delay );
            }
            doFade();
        }
        this.fadeOut = function( speed, callback ) {
            speed = speed || buzz.defaults.fadeSpeed;
            var delay = speed / this.volume,
                that = this;

            function doFade() {
                setTimeout( function() {
                    if ( that.volume > 0 ) {
                        that.setVolume( that.volume -= 1 );
                        doFade();
                    } else if ( callback instanceof Function ) {
                        callback.apply( that );
                    }
                }, delay );
            }
            doFade();
        }
        this.fadeWith = function( sound, speed ) {
            this.fadeOut( speed, function() {
                this.stop();
            });
            if ( sound instanceof buzz.sound) {
                sound.play().fadeIn( speed );
            }
        }
        this.whenReady = function( func ) {
            var that = this;
            if ( this.sound.readyState == 0 ) {
                this.bind( 'canplay.buzzwhenready', function() {
                    func.call( that );
                });
            } else {
                func.call( that );
            }
        }

        // init
        if ( supported ) {
            for( var i in buzz.defaults ) {
                options[ i ] = options[ i ] || buzz.defaults[ i ];
            }

            this.sound = document.createElement( 'audio' );
            if ( src instanceof Array ) {
                for( var i in src ) {
                    var source = document.createElement( 'source' );
                    source.src = src[ i ];
                    this.sound.appendChild( source );
                }
            } else if ( options.formats.length ) {
                for( var i in options.formats ) {
                    var source = document.createElement( 'source' );
                    source.src = src + '.' + options.formats[ i ];
                    this.sound.appendChild( source );
                }
            } else {
                this.sound.src = src;
            }
            if ( options.loop ) {
                this.loop();
            }
            if ( options.autoplay ) {
                this.sound.autoplay = 'autoplay';
            }
            this.sound.preload = options.preload;
            this.volume = options.volume;

            buzz.sounds.push( this );
        }
    },
    all: function() {
      return new buzz.group( buzz.sounds );
    },
    group: function( sounds ) {
        fn = function() {
            var args = Array.prototype.slice.call( arguments ),
                func = args.shift();

            for( var i in sounds ) {
                sounds[ i ][ func ].apply( sounds[ i ], args );
            }
        }
        this.play = function() {
            fn( 'play' );
            return this;
        }
        this.stop = function() {
            fn( 'stop' );
            return this;
        }
        this.pause = function( time ) {
            fn( 'pause', time );
            return this;
        }
        this.togglePlay = function( ) {
            fn( 'togglePlay' );
            return this;
        }
        this.mute = function() {
            fn( 'mute' );
            return this;
        }
        this.unmute = function() {
            fn( 'unmute' );
            return this;
        }
        this.toggleMute = function() {
            fn( 'toggleMute' );
            return this;
        }
        this.setVolume = function( volume ) {
            fn( 'setVolume', volume );
            return this;
        }
        this.increaseVolume = function( value ) {
            fn( 'increaseVolume', value );
            return this;
        }
        this.decreaseVolume = function( value ) {
            fn( 'decreaseVolume', value );
            return this;
        }
        this.loop = function() {
            fn( 'loop' );
            return this;
        }
        this.unloop = function() {
            fn( 'unloop' );
            return this;
        }
        this.setTime = function( time ) {
            fn( 'setTime', time );
            return this;
        }
        this.set = function( key, value ) {
            fn( 'set', key, value );
            return this;
        }
        this.bind = function( type, func ) {
            fn( 'bind', type, func );
            return this;
        }
        this.unbind = function( type ) {
            fn( 'unbind', type );
            return this;
        }
        this.destroy = function() {
            fn( 'destroy' );
            return this;
        }
        this.fade = function( from, to, speed, callback ) {
            fn( 'fade', from, to, speed, callback );
            return this;
        }
        this.fadeIn = function( speed, callback ) {
            fn( 'fadeIn', speed, callback );
            return this;
        }
        this.fadeOut = function( speed, callback ) {
            fn( 'fadeOut', speed, callback );
            return this;
        }
    },
    formatTime: function( s, withHours ) {
        h = Math.floor( s / 3600 );
        h = isNaN(h) ? '--' : ( h >= 10 ) ? h : '0' + h;
        m = withHours ? Math.floor( s / 60 % 60 ) : Math.floor( s / 60 );
        m = isNaN(m) ? '--' : ( m >= 10 ) ? m : '0' + m;
        s = Math.floor( s % 60 );
        s = isNaN(s) ? '--' : ( s >= 10 ) ? s : '0' + s;
        return withHours ? h + ':' + m + ':' + s : m + ':' + s;
    }
}<|endoftext|>


<commit_before>/*!
* Mediator.js Library v0.6.0
* https://github.com/ajacksified/Mediator.js
*
* Copyright 2011, Jack Lawson
* MIT Licensed (http://www.opensource.org/licenses/mit-license.php)
*
* For more information: http://www.thejacklawson.com/index.php/2011/06/mediators-for-modularized-asynchronous-programming-in-javascript/
* Project on GitHub: https://github.com/ajacksified/Mediator.js
*
* Last update: Sep 15 2011
*/

(function(){

  // We'll generate guids for class instances for easy referencing later on.
  // Subscriber instances will have an id that can be refernced for quick
  // lookups.

  function guidGenerator() {
    var S4 = function() {
       return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
    };
    return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
  }

  // Subscribers are instances of Mediator Channel registrations. We generate
  // an object instance so that it can be updated later on without having to
  // unregister and re-register. Subscribers are constructed with a function
  // to be called, options object, and context.

  function Subscriber(fn, options, context){
    if (!this instanceof Subscriber) {
      return new Subscriber(fn, context, options);
    }else{
      this.id = guidGenerator();
      this.fn = fn;
      this.options = options;
      this.context = context;
      this.channel = null;
    }
  };

  Subscriber.prototype = {

    // Mediator.Update on a subscriber instance can update its function,context,
    // or options object. It takes in an object and looks for fn, context, or
    // options keys.

    Update: function(options){
      if(options){
        this.fn = options.fn || this.fn;
        this.context = options.context || this.context;
        this.options = options.options || this.options;
      }
    },

    // Attach a channel to the Subscriber object to easy access

    SetChannel: function(channel){
      this.channel = channel;
    }
  };

  function Channel(namespace){
    if (!this instanceof Channel) {
      return new Channel(namespace);
    }else{
      this.namespace = namespace;
      this._callbacks = [];
      this._channels = [];
      this.stopped = false;
    }
  };

  // A Mediator channel holds a list of sub-channels and callbacks to be fired
  // when Mediator.Publish is called on the Mediator instance. It also contains
  // some methods to manipulate its lists of data; only SetPriority and
  // StopPropagation are meant to be used. The other methods should be accessed
  // through the Mediator instance.

  Channel.prototype = {
    AddSubscriber: function(fn, options, context){
      var callback = new Subscriber(fn, options, context);

      if(options && options.priority !== undefined){
        options.priority = options.priority >> 0;

        if(options.priority < 0) options.priority = 0;
        if(options.priority > this._callbacks.length) options.priority = this._callbacks.length;

        this._callbacks.splice(options.priority, 1, callback);
      }else{
        this._callbacks.push(callback);
      }

      callback.SetChannel(this);

      return callback;
    },

    // The channel instance is passed as an argument to the mediator callback,
    // and further callback propagation can be called with
    // channel.StopPropagation().
    StopPropagation: function(){
      this.stopped = true;
    },

    GetSubscriber: function(identifier){
      for(var x = 0, y = this._callbacks.length; x < y; x++){
        if(this._callbacks[x].id == identifier || this._callbacks[x].fn == identifier){
          return this._callbacks[x];
        }
      }

      for(var z in this._channels){
        if(this._channels.hasOwnProperty(z)){
          var sub = this._channels[z].GetSubscriber(identifier);
          if(sub !== undefined){
            return sub;
          }
        }
      }
    },

    // Channel.SetPriority is useful in updating the order in which Subscribers
    // are called, and takes an identifier (Callback id or named function) and
    // an array index. It will not search recursively through subchannels.

    SetPriority: function(identifier, priority){
      var oldIndex = 0;

      for(var x = 0, y = this._callbacks.length; x < y; x++){
        if(this._callbacks[x].id == identifier || this._callbacks[x].fn == identifier){
          break;
        }
        oldIndex ++;
      }

      var sub = this._callbacks[oldIndex],
          firstHalf = this._callbacks.slice(0, oldIndex),
          lastHalf = this._callbacks.slice(oldIndex+1);

      this._callbacks = firstHalf.concat(lastHalf);
      this._callbacks.splice(priority, 0, sub);

    },

    AddChannel: function(channel){
      this._channels[channel] = new Channel((this.namespace ? this.namespace + ':' : '') + channel);
    },

    HasChannel: function(channel){
      return this._channels.hasOwnProperty(channel);
    },

    ReturnChannel: function(channel){
      return this._channels[channel];
    },

    // This will remove a subscriber recursively through its subchannels.

    RemoveSubscriber: function(identifier){
      if(!identifier){
        this._callbacks = [];

        for(var z in this._channels){
          if(this._channels.hasOwnProperty(z)){
            this._channels[z].RemoveSubscriber(identifier);
          }
        }
      }

      for(var y = 0, x = this._callbacks.length; y < x; y++) {
        if(this._callbacks[y].fn == identifier || this._callbacks[y].id == identifier){
          this._callbacks[y].SetChannel(null);
          this._callbacks.splice(y,1);
          x--; y--;
        }
      }
    },

    // This will publish arbitrary arguments to a subscriber recursively
    // through its subchannels.

    Publish: function(data){
      for(var y = 0, x = this._callbacks.length; y < x; y++) {
        if(!this.stopped){
          var callback = this._callbacks[y];

          if(callback.options !== undefined && typeof callback.options.predicate === "function"){
            if(callback.options.predicate.apply(callback.context, data)){
              callback.fn.apply(callback.context, data);
            }
          }else{
            callback.fn.apply(callback.context, data);
          }
        }
      }

      for(var x in this._channels){
        if(!this.stopped){
          if(this._channels.hasOwnProperty(x)){
            this._channels[x].Publish(data);
          }
        }
      }

      this.stopped = false;
    }
  };

  function Mediator() {
    if (!this instanceof Mediator) {
      return new Mediator();
    }else{
      this._channels = new Channel('');
    }
  };

  // A Mediator instance is the interface through which events are registered
  // and removed from publish channels.

  Mediator.prototype = {

    // Returns a channel instance based on namespace, for example
    // application:chat:message:received

    GetChannel: function(namespace){
      var channel = this._channels;
      var namespaceHierarchy = namespace.split(':');

      if(namespace === ''){
        return channel;
      }

      if(namespaceHierarchy.length > 0){
        for(var i = 0, j = namespaceHierarchy.length; i < j; i++){

          if(!channel.HasChannel(namespaceHierarchy[i])){
            channel.AddChannel(namespaceHierarchy[i]);
          }

          channel = channel.ReturnChannel(namespaceHierarchy[i]);
        }
      }

      return channel;
    },

    // Pass in a channel namespace, function to be called, options, and context
    // to call the function in to Subscribe. It will create a channel if one
    // does not exist. Options can include a predicate to determine if it
    // should be called (based on the data published to it) and a priority
    // index.

    Subscribe: function(channelName, fn, options, context){
      var options = options || {},
          context = context || {},
          channel = this.GetChannel(channelName),
          sub = channel.AddSubscriber(fn, options, context);

      return sub;
    },

    // Returns a subscriber for a given subscriber id / named function and
    // channel namespace

    GetSubscriber: function(identifier, channel){
      return this.GetChannel(channel || "").GetSubscriber(identifier);
    },

    // Remove a subscriber from a given channel namespace recursively based on
    // a passed-in subscriber id or named function.

    Remove: function(channelName, identifier){
      this.GetChannel(channelName).RemoveSubscriber(identifier);
    },

    // Publishes arbitrary data to a given channel namespace. Channels are
    // called recursively downwards; a post to application:chat will post to
    // application:chat:receive and application:chat:derp:test:beta:bananas.
    // Called using Mediator.Publish("application:chat", [ args ]);

    Publish: function(channelName){
      var args = Array.prototype.slice.call(arguments, 1),
          channel = this.GetChannel(channelName);

      args.push(channel);

      this.GetChannel(channelName).Publish(args);
    }
  };

  // Finally, expose it all.

  window.Mediator = Mediator;
  Mediator.Channel = Channel;
  Mediator.Subscriber = Subscriber;
})(window);

<commit_msg>Really update the priority of a subscriber when it is updated via its Update method<commit_after>/*!
* Mediator.js Library v0.6.0
* https://github.com/ajacksified/Mediator.js
*
* Copyright 2011, Jack Lawson
* MIT Licensed (http://www.opensource.org/licenses/mit-license.php)
*
* For more information: http://www.thejacklawson.com/index.php/2011/06/mediators-for-modularized-asynchronous-programming-in-javascript/
* Project on GitHub: https://github.com/ajacksified/Mediator.js
*
* Last update: Sep 15 2011
*/

(function(){

  // We'll generate guids for class instances for easy referencing later on.
  // Subscriber instances will have an id that can be refernced for quick
  // lookups.

  function guidGenerator() {
    var S4 = function() {
       return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
    };
    return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
  }

  // Subscribers are instances of Mediator Channel registrations. We generate
  // an object instance so that it can be updated later on without having to
  // unregister and re-register. Subscribers are constructed with a function
  // to be called, options object, and context.

  function Subscriber(fn, options, context){
    if (!this instanceof Subscriber) {
      return new Subscriber(fn, context, options);
    }else{
      this.id = guidGenerator();
      this.fn = fn;
      this.options = options;
      this.context = context;
      this.channel = null;
    }
  };

  Subscriber.prototype = {

    // Mediator.Update on a subscriber instance can update its function,context,
    // or options object. It takes in an object and looks for fn, context, or
    // options keys.

    Update: function(options){
      if(options){
        this.fn = options.fn || this.fn;
        this.context = options.context || this.context;
        this.options = options.options || this.options;
        if (this.channel && this.options && this.options.priority != undefined) {
            this.channel.SetPriority(this.id, this.options.priority);
        }
      }
    },

    // Attach a channel to the Subscriber object to easy access

    SetChannel: function(channel){
      this.channel = channel;
    }
  };

  function Channel(namespace){
    if (!this instanceof Channel) {
      return new Channel(namespace);
    }else{
      this.namespace = namespace;
      this._callbacks = [];
      this._channels = [];
      this.stopped = false;
    }
  };

  // A Mediator channel holds a list of sub-channels and callbacks to be fired
  // when Mediator.Publish is called on the Mediator instance. It also contains
  // some methods to manipulate its lists of data; only SetPriority and
  // StopPropagation are meant to be used. The other methods should be accessed
  // through the Mediator instance.

  Channel.prototype = {
    AddSubscriber: function(fn, options, context){
      var callback = new Subscriber(fn, options, context);

      if(options && options.priority !== undefined){
        options.priority = options.priority >> 0;

        if(options.priority < 0) options.priority = 0;
        if(options.priority > this._callbacks.length) options.priority = this._callbacks.length;

        this._callbacks.splice(options.priority, 1, callback);
      }else{
        this._callbacks.push(callback);
      }

      callback.SetChannel(this);

      return callback;
    },

    // The channel instance is passed as an argument to the mediator callback,
    // and further callback propagation can be called with
    // channel.StopPropagation().
    StopPropagation: function(){
      this.stopped = true;
    },

    GetSubscriber: function(identifier){
      for(var x = 0, y = this._callbacks.length; x < y; x++){
        if(this._callbacks[x].id == identifier || this._callbacks[x].fn == identifier){
          return this._callbacks[x];
        }
      }

      for(var z in this._channels){
        if(this._channels.hasOwnProperty(z)){
          var sub = this._channels[z].GetSubscriber(identifier);
          if(sub !== undefined){
            return sub;
          }
        }
      }
    },

    // Channel.SetPriority is useful in updating the order in which Subscribers
    // are called, and takes an identifier (Callback id or named function) and
    // an array index. It will not search recursively through subchannels.

    SetPriority: function(identifier, priority){
      var oldIndex = 0;

      for(var x = 0, y = this._callbacks.length; x < y; x++){
        if(this._callbacks[x].id == identifier || this._callbacks[x].fn == identifier){
          break;
        }
        oldIndex ++;
      }

      var sub = this._callbacks[oldIndex],
          firstHalf = this._callbacks.slice(0, oldIndex),
          lastHalf = this._callbacks.slice(oldIndex+1);

      this._callbacks = firstHalf.concat(lastHalf);
      this._callbacks.splice(priority, 0, sub);

    },

    AddChannel: function(channel){
      this._channels[channel] = new Channel((this.namespace ? this.namespace + ':' : '') + channel);
    },

    HasChannel: function(channel){
      return this._channels.hasOwnProperty(channel);
    },

    ReturnChannel: function(channel){
      return this._channels[channel];
    },

    // This will remove a subscriber recursively through its subchannels.

    RemoveSubscriber: function(identifier){
      if(!identifier){
        this._callbacks = [];

        for(var z in this._channels){
          if(this._channels.hasOwnProperty(z)){
            this._channels[z].RemoveSubscriber(identifier);
          }
        }
      }

      for(var y = 0, x = this._callbacks.length; y < x; y++) {
        if(this._callbacks[y].fn == identifier || this._callbacks[y].id == identifier){
          this._callbacks[y].SetChannel(null);
          this._callbacks.splice(y,1);
          x--; y--;
        }
      }
    },

    // This will publish arbitrary arguments to a subscriber recursively
    // through its subchannels.

    Publish: function(data){
      for(var y = 0, x = this._callbacks.length; y < x; y++) {
        if(!this.stopped){
          var callback = this._callbacks[y];

          if(callback.options !== undefined && typeof callback.options.predicate === "function"){
            if(callback.options.predicate.apply(callback.context, data)){
              callback.fn.apply(callback.context, data);
            }
          }else{
            callback.fn.apply(callback.context, data);
          }
        }
      }

      for(var x in this._channels){
        if(!this.stopped){
          if(this._channels.hasOwnProperty(x)){
            this._channels[x].Publish(data);
          }
        }
      }

      this.stopped = false;
    }
  };

  function Mediator() {
    if (!this instanceof Mediator) {
      return new Mediator();
    }else{
      this._channels = new Channel('');
    }
  };

  // A Mediator instance is the interface through which events are registered
  // and removed from publish channels.

  Mediator.prototype = {

    // Returns a channel instance based on namespace, for example
    // application:chat:message:received

    GetChannel: function(namespace){
      var channel = this._channels;
      var namespaceHierarchy = namespace.split(':');

      if(namespace === ''){
        return channel;
      }

      if(namespaceHierarchy.length > 0){
        for(var i = 0, j = namespaceHierarchy.length; i < j; i++){

          if(!channel.HasChannel(namespaceHierarchy[i])){
            channel.AddChannel(namespaceHierarchy[i]);
          }

          channel = channel.ReturnChannel(namespaceHierarchy[i]);
        }
      }

      return channel;
    },

    // Pass in a channel namespace, function to be called, options, and context
    // to call the function in to Subscribe. It will create a channel if one
    // does not exist. Options can include a predicate to determine if it
    // should be called (based on the data published to it) and a priority
    // index.

    Subscribe: function(channelName, fn, options, context){
      var options = options || {},
          context = context || {},
          channel = this.GetChannel(channelName),
          sub = channel.AddSubscriber(fn, options, context);

      return sub;
    },

    // Returns a subscriber for a given subscriber id / named function and
    // channel namespace

    GetSubscriber: function(identifier, channel){
      return this.GetChannel(channel || "").GetSubscriber(identifier);
    },

    // Remove a subscriber from a given channel namespace recursively based on
    // a passed-in subscriber id or named function.

    Remove: function(channelName, identifier){
      this.GetChannel(channelName).RemoveSubscriber(identifier);
    },

    // Publishes arbitrary data to a given channel namespace. Channels are
    // called recursively downwards; a post to application:chat will post to
    // application:chat:receive and application:chat:derp:test:beta:bananas.
    // Called using Mediator.Publish("application:chat", [ args ]);

    Publish: function(channelName){
      var args = Array.prototype.slice.call(arguments, 1),
          channel = this.GetChannel(channelName);

      args.push(channel);

      this.GetChannel(channelName).Publish(args);
    }
  };

  // Finally, expose it all.

  window.Mediator = Mediator;
  Mediator.Channel = Channel;
  Mediator.Subscriber = Subscriber;
})(window);

<|endoftext|>