<commit_before>var Views = {};
Views.ListingView = Backbone.View.extend({
	initialize: function() {
		this.listenTo(this.collection, 'add', this.collectionAdded);
		this.listenTo(this.collection, 'change', this.collectionChanged);
		this.listenTo(this.collection, 'remove', this.collectionRemoved);

		this.childViews = [];

		this._addAllModels();
	},

	events: {
		"click span#add-item" : "addItemClick"
	},

	render: function() {
		var fragment = document.createDocumentFragment();

		if(this.childViews.length > 0) {
			_(this.childViews).each(function(currentView) {
				fragment.appendChild(currentView.render().el);
			});
		} else {
			$(Templates.EmptyListingTemplate()).appendTo(fragment);
		}

		this.$('.item-listing').html(fragment);
		return this;
	},

	collectionAdded: function(item) {
		this._addViewForModel(item);
		this.render();
	},

	collectionRemoved: function(item) {
		this.childViews = this.childViews.filter(function(view) {
			return view.model.id !== item.id;
		});
		this.render();
	},

	collectionChanged: function() {
		this.childViews = [];
		this._addAllModels();
	},

	addItemClick: function() {

	},

	_addViewForModel: function(item) {
		this.childViews.push(new Views.ItemView({
			model: item
		}));
	},

	_addAllModels: function() {
		this.collection.each(function(item) {
			_addViewForModel(item);
		});
		this.render();
	}
});

Views.ItemView = Backbone.View.extend({
	template: Templates.ItemListingTemplate,

	events: {
		"click button#btn-pledge" : "pledgeClick"
	},

	pledgeClick: function() {

	},

	initialize: function() {
		this.listenTo(this.model, "change", this.render);
		this.id = "item-" + this.model.attributes.id;
	},

	render: function() {
		this.$el.html(this.template(this.model.attributes));
		return this;
	}
});

Views.SearchFormView = Backbone.View.extend({
	template: Templates.SearchFormTemplate,

	events: {
		"click a#btn-search" : "searchClick"
	},

	searchClick: function() {
        var search = $('#txt-search').val();
		$('#search-results').show();
        this.searchCollection.fetch({ data: $.param({ search:search }) });
	},

	initialize: function() {
        this.searchCollection = new Models.SearchResults();
        this.searchListingView = new Views.SearchListingView({
            collection: this.searchCollection,
            el: '#search-results',
            id: 'search-results'
        });
	},

	render: function() {
		this.$el.html(this.template());
		return this;
	}
});

Views.SearchListingView = Backbone.View.extend({
	initialize: function() {
		this.listenTo(this.collection, 'add', this.collectionAdded);
		this.listenTo(this.collection, 'change', this.collectionChanged);
		this.listenTo(this.collection, 'remove', this.collectionRemoved);

		this.childViews = [];

		this._addAllModels();
	},

	render: function() {
		var fragment = document.createDocumentFragment();
		this.$('.item-listing').html(fragment);
		return this;
	},

	collectionAdded: function(item) {
		this._addViewForModel(item);
		this.render();
	},

	collectionRemoved: function(item) {
		this.childViews = this.childViews.filter(function(view) {
			return view.model.id !== item.id;
		});
		this.render();
	},

	collectionChanged: function() {
		this.childViews = [];
		this._addAllModels();
	},

	_addViewForModel: function(item) {
		this.childViews.push(new Views.SearchView({
			model: item
		}));
	},

	_addAllModels: function() {
		this.collection.each(function(item) {
			_addViewForModel(item);
		});
		this.render();
	}
});

Views.SearchView = Backbone.View.extend({
	template: Templates.SearchListingTemplate,

	events: {
		"click button#btn-pledge" : "pledgeClick"
	},

	pledgeClick: function() {

	},

	initialize: function() {
		this.listenTo(this.model, "change", this.render);
		this.id = "item-" + this.model.attributes.id;
	},

	initialize: function() {
		this.listenTo(this.model, "change", this.render);
		this.id = "search-" + this.model.attributes.id;
	},

	render: function() {
		this.$el.html(this.template(this.model.attributes));
		return this;
	}
});<commit_msg>fixed search GET<commit_after>var Views = {};
Views.ListingView = Backbone.View.extend({
	initialize: function() {
		this.listenTo(this.collection, 'add', this.collectionAdded);
		this.listenTo(this.collection, 'change', this.collectionChanged);
		this.listenTo(this.collection, 'remove', this.collectionRemoved);

		this.childViews = [];

		this._addAllModels();
	},

	events: {
		"click span#add-item" : "addItemClick"
	},

	render: function() {
		var fragment = document.createDocumentFragment();

		if(this.childViews.length > 0) {
			_(this.childViews).each(function(currentView) {
				fragment.appendChild(currentView.render().el);
			});
		} else {
			$(Templates.EmptyListingTemplate()).appendTo(fragment);
		}

		this.$('.item-listing').html(fragment);
		return this;
	},

	collectionAdded: function(item) {
		this._addViewForModel(item);
		this.render();
	},

	collectionRemoved: function(item) {
		this.childViews = this.childViews.filter(function(view) {
			return view.model.id !== item.id;
		});
		this.render();
	},

	collectionChanged: function() {
		this.childViews = [];
		this._addAllModels();
	},

	addItemClick: function() {

	},

	_addViewForModel: function(item) {
		this.childViews.push(new Views.ItemView({
			model: item
		}));
	},

	_addAllModels: function() {
		this.collection.each(function(item) {
			_addViewForModel(item);
		});
		this.render();
	}
});

Views.ItemView = Backbone.View.extend({
	template: Templates.ItemListingTemplate,

	events: {
		"click button#btn-pledge" : "pledgeClick"
	},

	pledgeClick: function() {

	},

	initialize: function() {
		this.listenTo(this.model, "change", this.render);
		this.id = "item-" + this.model.attributes.id;
	},

	render: function() {
		this.$el.html(this.template(this.model.attributes));
		return this;
	}
});

Views.SearchFormView = Backbone.View.extend({
	template: Templates.SearchFormTemplate,

	events: {
		"click a#btn-search" : "searchClick"
	},

	searchClick: function() {
        var search = $('#txt-search').val();
		$('#search-results').show();
        this.searchCollection.url = '/service/products/results/' + search;
        this.searchCollection.fetch();
	},

	initialize: function() {
        this.searchCollection = new Models.SearchResults();
        this.searchListingView = new Views.SearchListingView({
            collection: this.searchCollection,
            el: '#search-results',
            id: 'search-results'
        });
	},

	render: function() {
		this.$el.html(this.template());
		return this;
	}
});

Views.SearchListingView = Backbone.View.extend({
	initialize: function() {
		this.listenTo(this.collection, 'add', this.collectionAdded);
		this.listenTo(this.collection, 'change', this.collectionChanged);
		this.listenTo(this.collection, 'remove', this.collectionRemoved);

		this.childViews = [];

		this._addAllModels();
	},

	render: function() {
		var fragment = document.createDocumentFragment();
		this.$('.item-listing').html(fragment);
		return this;
	},

	collectionAdded: function(item) {
		this._addViewForModel(item);
		this.render();
	},

	collectionRemoved: function(item) {
		this.childViews = this.childViews.filter(function(view) {
			return view.model.id !== item.id;
		});
		this.render();
	},

	collectionChanged: function() {
		this.childViews = [];
		this._addAllModels();
	},

	_addViewForModel: function(item) {
		this.childViews.push(new Views.SearchView({
			model: item
		}));
	},

	_addAllModels: function() {
		this.collection.each(function(item) {
			_addViewForModel(item);
		});
		this.render();
	}
});

Views.SearchView = Backbone.View.extend({
	template: Templates.SearchListingTemplate,

	events: {
		"click button#btn-pledge" : "pledgeClick"
	},

	pledgeClick: function() {

	},

	initialize: function() {
		this.listenTo(this.model, "change", this.render);
		this.id = "item-" + this.model.attributes.id;
	},

	initialize: function() {
		this.listenTo(this.model, "change", this.render);
		this.id = "search-" + this.model.attributes.id;
	},

	render: function() {
		this.$el.html(this.template(this.model.attributes));
		return this;
	}
});<|endoftext|>


<commit_before>/* See license.txt for terms of usage */

"use strict";

module.metadata = {
  "stability": "experimental"
};

// Add-on SDK
const { Cu, Ci } = require("chrome");
const { EventTarget } = require("sdk/event/target");
const { extend } = require("sdk/core/heritage");
const { defer, resolve } = require("sdk/core/promise");

// Firebug SDK
const { Trace, TraceError } = require("./core/trace.js").get(module.id);
const { Context } = require("./context.js");
const { Dispatcher } = require("./dispatcher.js");

// DevTools
const { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});

/**
 * TODO docs
 */
var ToolboxChrome = extend(EventTarget.prototype,
/** @lends ToolboxChrome */
{
  // Initialization

  initialize: function() {
    this.initialized = true;
    this.contexts = new Map();
    this.registeredOverlays = new Map();

    // Bind DevTools event handlers.
    this.onToolboxCreated = this.onToolboxCreated.bind(this);
    this.onToolboxReady = this.onToolboxReady.bind(this);
    this.onToolboxDestroy = this.onToolboxDestroy.bind(this);
    this.onToolboxClosed = this.onToolboxClosed.bind(this);

    // Hook developer tools events.
    gDevTools.on("toolbox-created", this.onToolboxCreated);
    gDevTools.on("toolbox-ready", this.onToolboxReady);
    gDevTools.on("toolbox-destroy", this.onToolboxDestroy);
    gDevTools.on("toolbox-destroyed", this.onToolboxClosed);

    Dispatcher.emit("initialize");
  },

  shutdown: function() {
    gDevTools.off("toolbox-created", this.onToolboxCreated);
    gDevTools.off("toolbox-ready", this.onToolboxReady);
    gDevTools.off("toolbox-destroy", this.onToolboxDestroy);
    gDevTools.off("toolbox-destroyed", this.onToolboxClosed);

    Dispatcher.emit("shutdown");
  },

  // DevTools Event Handlers

  onToolboxCreated: function(eventId, toolbox) {
    Trace.sysout("ToolboxChrome.onToolboxCreated;", toolbox);

    // Make sure to create the toolbox context as soon as possible.
    // 'toolbox-created' has been introduced in Fx 39, so use
    // 'toolbox-ready' for previous versions.
    let context = this.getContext(toolbox);

    Dispatcher.emit("onToolboxCreated", arguments);
  },

  onToolboxReady: function(event, toolbox) {
    Trace.sysout("ToolboxChrome.onToolboxReady; ", toolbox);

    // Make sure to create the toolbox context as soon as possible.
    let context = this.getContext(toolbox);

    Dispatcher.emit("onToolboxReady", arguments);
  },

  onToolboxDestroy: function(eventId, target) {
    Trace.sysout("ToolboxChrome.onToolboxDestroy;", target);

    let context = this.contexts.get(target);
    if (!context) {
      Trace.sysout("ToolboxChrome.onToolboxDestroy; ERROR unknown target!",
        target);
      return;
    }

    Dispatcher.emit("onToolboxDestroy", arguments);

    this.contexts.delete(target);

    context.destroy();
  },

  onToolboxClosed: function(eventId, target) {
    Trace.sysout("ToolboxChrome.onToolboxClosed;", target);

    let context = this.contexts.get(target);
    if (!context) {
      Trace.sysout("ToolboxChrome.onToolboxClosed; ERROR unknown target!",
        target);
      return;
    }
  },

  // Overlays

  registerPanelOverlay: function(overlay) {
    let overlayId = overlay.prototype.overlayId;
    let panelId = overlay.prototype.panelId;

    Trace.sysout("ToolboxChrome.registerOverlay; " + overlayId, overlay);

    // Listen for panel initialization event.
    let onApplyOverlay = (eventId, toolbox, panelFrame) => {
      Trace.sysout("ToolboxChrome.onApplyOverlay; " + overlayId, panelFrame);

      let context = this.getContext(toolbox);

      // Bail out if the overlay already exists for this context/toolbox.
      if (context.getOverlay(overlayId)) {
        return;
      }

      try {
        // Create instance of an overlay
        let instance = new overlay({
          panelFrame: panelFrame,
          toolbox: toolbox,
          chrome: this,
          context: context
        });

        context.overlays.set(overlayId, instance);

        // Register for 'build' event (panel instance created).
        toolbox.once(panelId + "-build", (eventId, panel) => {
          Trace.sysout("ToolboxChrome.applyOverlay; " + eventId, panel);
          instance.onBuild({toolbox: toolbox, panel: panel});
        });

        // Register for 'ready' event (panel frame loaded).
        toolbox.once(panelId + "-ready", (eventId, panel) => {
          Trace.sysout("ToolboxChrome.applyOverlay; " + eventId, panel);
          instance.onReady({toolbox: toolbox, panel: panel});
        });
      }
      catch (err) {
        TraceError.sysout("ToolboxChrome.initialize; Overlay for: " +
          overlay.id + " EXCEPTION " + err, err);
      }
    };

    // Use 'on' (not 'once') listener since the '*-init' event is sent
    // every time the toolbox is closed and opened again. The listener
    // will be removed in destroyOverlay method when the extension is
    // destroyed.
    gDevTools.on(panelId + "-init", onApplyOverlay);

    this.registeredOverlays.set(overlayId, {
      ctor: overlay,
      creator: onApplyOverlay
    })
  },

  unregisterPanelOverlay: function(overlay) {
    let overlayId = overlay.prototype.overlayId;

    Trace.sysout("ToolboxChrome.unregisterOverlay; " + overlayId, overlay);

    let entry = this.registeredOverlays.get(overlayId);
    gDevTools.off(overlayId + "-init", entry.creator);

    this.registeredOverlays.delete(overlayId);
  },

  registerToolboxOverlay: function(overlay) {
    let overlayId = overlay.prototype.overlayId;

    Trace.sysout("ToolboxChrome.registerToolboxOverlay; " +
      overlayId, overlay);

    let onApplyOverlay = (eventId, toolbox) => {
      Trace.sysout("ToolboxChrome.onApplyToolboxOverlay; " +
        overlayId, toolbox);

      let context = this.getContext(toolbox);

      // Bail out if the overlay already exists for this context/toolbox.
      if (context.getOverlay(overlayId)) {
        return;
      }

      try {
        // Create instance of an overlay
        let instance = new overlay({
          toolbox: toolbox,
          chrome: this,
          context: context,
        });

        context.overlays.set(overlayId, instance);

        // Execute 'onReady' on the overlay instance when the toolbox
        // is ready. There are two options, (a) the toolbox is already
        // ready at this point (extension installed dynamically in the
        // middle of Firefox session), (b) the toolbox is not ready yet
        // and it's necessary to wait for the event.
        if (toolbox.isReady) {
          instance.onReady({toolbox: toolbox});
        } else {
          gDevTools.once("toolbox-ready", () => {
            instance.onReady({toolbox: toolbox});
          });
        }
      }
      catch (err) {
        TraceError.sysout("ToolboxChrome.initialize; Overlay for: " +
          overlay.id + " EXCEPTION " + err, err);
      }
    };

    // Use 'on' (not 'once') listener since the create event is sent
    // every time a toolbox is created (can be also on another browser tab).
    gDevTools.on("toolbox-created", onApplyOverlay);

    this.registeredOverlays.set(overlayId, {
      ctor: overlay,
      creator: onApplyOverlay
    })

    // Apply the overlay on all existing toolboxes. Registered toolbox
    // overlays must be always instantiated before registered panel
    // overlays.
    for (let [target, toolbox] of gDevTools._toolboxes) {
      target.makeRemote().then(() => {
        onApplyOverlay(null, toolbox);
      });
    }
  },

  unregisterToolboxOverlay: function(overlay) {
    let overlayId = overlay.prototype.overlayId;

    Trace.sysout("ToolboxChrome.unregisterToolboxOverlay; " +
      overlayId, overlay);

    let entry = this.registeredOverlays.get(overlayId);
    gDevTools.off("toolbox-ready", entry.creator);

    this.registeredOverlays.delete(overlayId);
  },

  // Context

  getContext: function(toolbox) {
    let target = toolbox.target;
    let context = this.contexts.get(target);
    if (!context) {
      context = new Context(toolbox);
      this.contexts.set(target, context);
    }
    return context;
  },
});

function getToolboxWhenReady(toolId) {
  let deferred = defer();
  showToolbox(toolId).then(toolbox => {
    deferred.resolve(toolbox);
  });
  return deferred.promise;
}

// Exports from this module
exports.ToolboxChrome = ToolboxChrome;
<commit_msg>Return value from toolbox-chrome<commit_after>/* See license.txt for terms of usage */

"use strict";

module.metadata = {
  "stability": "experimental"
};

// Add-on SDK
const { Cu, Ci } = require("chrome");
const { EventTarget } = require("sdk/event/target");
const { extend } = require("sdk/core/heritage");
const { defer, resolve } = require("sdk/core/promise");

// Firebug SDK
const { Trace, TraceError } = require("./core/trace.js").get(module.id);
const { Context } = require("./context.js");
const { Dispatcher } = require("./dispatcher.js");

// DevTools
const { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});

/**
 * TODO docs
 */
var ToolboxChrome = extend(EventTarget.prototype,
/** @lends ToolboxChrome */
{
  // Initialization

  initialize: function() {
    this.initialized = true;
    this.contexts = new Map();
    this.registeredOverlays = new Map();

    // Bind DevTools event handlers.
    this.onToolboxCreated = this.onToolboxCreated.bind(this);
    this.onToolboxReady = this.onToolboxReady.bind(this);
    this.onToolboxDestroy = this.onToolboxDestroy.bind(this);
    this.onToolboxClosed = this.onToolboxClosed.bind(this);

    // Hook developer tools events.
    gDevTools.on("toolbox-created", this.onToolboxCreated);
    gDevTools.on("toolbox-ready", this.onToolboxReady);
    gDevTools.on("toolbox-destroy", this.onToolboxDestroy);
    gDevTools.on("toolbox-destroyed", this.onToolboxClosed);

    return Dispatcher.emit("initialize");
  },

  shutdown: function() {
    gDevTools.off("toolbox-created", this.onToolboxCreated);
    gDevTools.off("toolbox-ready", this.onToolboxReady);
    gDevTools.off("toolbox-destroy", this.onToolboxDestroy);
    gDevTools.off("toolbox-destroyed", this.onToolboxClosed);

    return Dispatcher.emit("shutdown");
  },

  // DevTools Event Handlers

  onToolboxCreated: function(eventId, toolbox) {
    Trace.sysout("ToolboxChrome.onToolboxCreated;", toolbox);

    // Make sure to create the toolbox context as soon as possible.
    // 'toolbox-created' has been introduced in Fx 39, so use
    // 'toolbox-ready' for previous versions.
    let context = this.getContext(toolbox);

    Dispatcher.emit("onToolboxCreated", arguments);
  },

  onToolboxReady: function(event, toolbox) {
    Trace.sysout("ToolboxChrome.onToolboxReady; ", toolbox);

    // Make sure to create the toolbox context as soon as possible.
    let context = this.getContext(toolbox);

    Dispatcher.emit("onToolboxReady", arguments);
  },

  onToolboxDestroy: function(eventId, target) {
    Trace.sysout("ToolboxChrome.onToolboxDestroy;", target);

    let context = this.contexts.get(target);
    if (!context) {
      Trace.sysout("ToolboxChrome.onToolboxDestroy; ERROR unknown target!",
        target);
      return;
    }

    Dispatcher.emit("onToolboxDestroy", arguments);

    this.contexts.delete(target);

    context.destroy();
  },

  onToolboxClosed: function(eventId, target) {
    Trace.sysout("ToolboxChrome.onToolboxClosed;", target);

    let context = this.contexts.get(target);
    if (!context) {
      Trace.sysout("ToolboxChrome.onToolboxClosed; ERROR unknown target!",
        target);
      return;
    }
  },

  // Overlays

  registerPanelOverlay: function(overlay) {
    let overlayId = overlay.prototype.overlayId;
    let panelId = overlay.prototype.panelId;

    Trace.sysout("ToolboxChrome.registerOverlay; " + overlayId, overlay);

    // Listen for panel initialization event.
    let onApplyOverlay = (eventId, toolbox, panelFrame) => {
      Trace.sysout("ToolboxChrome.onApplyOverlay; " + overlayId, panelFrame);

      let context = this.getContext(toolbox);

      // Bail out if the overlay already exists for this context/toolbox.
      if (context.getOverlay(overlayId)) {
        return;
      }

      try {
        // Create instance of an overlay
        let instance = new overlay({
          panelFrame: panelFrame,
          toolbox: toolbox,
          chrome: this,
          context: context
        });

        context.overlays.set(overlayId, instance);

        // Register for 'build' event (panel instance created).
        toolbox.once(panelId + "-build", (eventId, panel) => {
          Trace.sysout("ToolboxChrome.applyOverlay; " + eventId, panel);
          instance.onBuild({toolbox: toolbox, panel: panel});
        });

        // Register for 'ready' event (panel frame loaded).
        toolbox.once(panelId + "-ready", (eventId, panel) => {
          Trace.sysout("ToolboxChrome.applyOverlay; " + eventId, panel);
          instance.onReady({toolbox: toolbox, panel: panel});
        });
      }
      catch (err) {
        TraceError.sysout("ToolboxChrome.initialize; Overlay for: " +
          overlay.id + " EXCEPTION " + err, err);
      }
    };

    // Use 'on' (not 'once') listener since the '*-init' event is sent
    // every time the toolbox is closed and opened again. The listener
    // will be removed in destroyOverlay method when the extension is
    // destroyed.
    gDevTools.on(panelId + "-init", onApplyOverlay);

    this.registeredOverlays.set(overlayId, {
      ctor: overlay,
      creator: onApplyOverlay
    })
  },

  unregisterPanelOverlay: function(overlay) {
    let overlayId = overlay.prototype.overlayId;

    Trace.sysout("ToolboxChrome.unregisterOverlay; " + overlayId, overlay);

    let entry = this.registeredOverlays.get(overlayId);
    gDevTools.off(overlayId + "-init", entry.creator);

    this.registeredOverlays.delete(overlayId);
  },

  registerToolboxOverlay: function(overlay) {
    let overlayId = overlay.prototype.overlayId;

    Trace.sysout("ToolboxChrome.registerToolboxOverlay; " +
      overlayId, overlay);

    let onApplyOverlay = (eventId, toolbox) => {
      Trace.sysout("ToolboxChrome.onApplyToolboxOverlay; " +
        overlayId, toolbox);

      let context = this.getContext(toolbox);

      // Bail out if the overlay already exists for this context/toolbox.
      if (context.getOverlay(overlayId)) {
        return;
      }

      try {
        // Create instance of an overlay
        let instance = new overlay({
          toolbox: toolbox,
          chrome: this,
          context: context,
        });

        context.overlays.set(overlayId, instance);

        // Execute 'onReady' on the overlay instance when the toolbox
        // is ready. There are two options, (a) the toolbox is already
        // ready at this point (extension installed dynamically in the
        // middle of Firefox session), (b) the toolbox is not ready yet
        // and it's necessary to wait for the event.
        if (toolbox.isReady) {
          instance.onReady({toolbox: toolbox});
        } else {
          gDevTools.once("toolbox-ready", () => {
            instance.onReady({toolbox: toolbox});
          });
        }
      }
      catch (err) {
        TraceError.sysout("ToolboxChrome.initialize; Overlay for: " +
          overlay.id + " EXCEPTION " + err, err);
      }
    };

    // Use 'on' (not 'once') listener since the create event is sent
    // every time a toolbox is created (can be also on another browser tab).
    gDevTools.on("toolbox-created", onApplyOverlay);

    this.registeredOverlays.set(overlayId, {
      ctor: overlay,
      creator: onApplyOverlay
    })

    // Apply the overlay on all existing toolboxes. Registered toolbox
    // overlays must be always instantiated before registered panel
    // overlays.
    for (let [target, toolbox] of gDevTools._toolboxes) {
      target.makeRemote().then(() => {
        onApplyOverlay(null, toolbox);
      });
    }
  },

  unregisterToolboxOverlay: function(overlay) {
    let overlayId = overlay.prototype.overlayId;

    Trace.sysout("ToolboxChrome.unregisterToolboxOverlay; " +
      overlayId, overlay);

    let entry = this.registeredOverlays.get(overlayId);
    gDevTools.off("toolbox-ready", entry.creator);

    this.registeredOverlays.delete(overlayId);
  },

  // Context

  getContext: function(toolbox) {
    let target = toolbox.target;
    let context = this.contexts.get(target);
    if (!context) {
      context = new Context(toolbox);
      this.contexts.set(target, context);
    }
    return context;
  },
});

function getToolboxWhenReady(toolId) {
  let deferred = defer();
  showToolbox(toolId).then(toolbox => {
    deferred.resolve(toolbox);
  });
  return deferred.promise;
}

// Exports from this module
exports.ToolboxChrome = ToolboxChrome;
<|endoftext|>


<commit_before>'use strict';
const moment = require('moment');
require('moment-timezone');

module.exports = function TwitchMessages(client) {
  const modChannel = client.channels.get('252275732628242432') || client.channels.get('373924698075037706');
  if (!modChannel) {
    client.utils.ownerError('twitchMessages', client, 'Unable to find Mod Channel');
    return;
  }
  const streamInfoSocket = require('socket.io-client')('ws://info.annemunition.tv');
  streamInfoSocket.on('connect', () => {
    client.logger.info('connected to streamInfo websocket');
  });
  streamInfoSocket.on('disconnect', () => {
    client.logger.warn('disconnected from streamInfo websocket');
  });
  streamInfoSocket.on('discord_ban_event', async data => {
    client.logger.debug(data);
    if (!data) return;
    if (typeof data !== 'object') return;
    if (Array.isArray(data)) return;
    if (!modChannel) return;
    client.logger.debug('discord_ban_event received');
    const messages = data.messages
      .sort(x => -parseInt(x.userstate['tmi-sent-ts']))
      .map(x => {
        const time = moment(parseInt(x.userstate['tmi-sent-ts']));
        return `\`\`[${time.tz('America/Los_Angeles').format('MM/DD/YY HH:mm:ss')}]\`\` ${x.message}`;
      });
    const embed = new client.Discord.MessageEmbed()
      .setAuthor(data.banee, await client.twitch.getUserLogo(data.banee_id),
        `https://www.twitch.tv/${data.banee.toLowerCase()}`)
      .setColor('DARK_ORANGE')
      .setDescription(messages.join('\n'))
      .setFooter(`Banned by ${data.banear}`)
      .setTimestamp(new Date(data.time));
    if (data.reason) embed.addField('Ban Reason:', data.reason);
    if (!['SEND_MESSAGES', 'EMBED_LINKS'].every(perm => modChannel.permissionsFor(client.user).has(perm))) {
      client.utils.ownerError('twitchMessages', client, 'Missing Channel Permissions');
      return;
    }
    modChannel.send({ embed })
      .catch(err => {
        client.utils.ownerError('twitchMessages', client, err);
      });
  });

  streamInfoSocket.on('discord_unban_event', async data => {
    client.logger.debug(data);
    if (!data) return;
    if (typeof data !== 'object') return;
    if (Array.isArray(data)) return;
    if (!modChannel) return;
    client.logger.debug('discord_unban_event received');
    const embed = new client.Discord.MessageEmbed()
      .setAuthor(data.banee, await client.twitch.getUserLogo(data.banee_id),
        `https://www.twitch.tv/${data.banee.toLowerCase()}`)
      .setColor('DARK_BLUE')
      .setFooter(`Unbanned by ${data.banear}`)
      .setTimestamp(new Date(data.time));
    if (!['SEND_MESSAGES', 'EMBED_LINKS'].every(perm => modChannel.permissionsFor(client.user).has(perm))) {
      client.utils.ownerError('twitchMessages', client, 'Missing Channel Permissions');
      return;
    }
    modChannel.send({ embed })
      .catch(err => {
        client.utils.ownerError('twitchMessages', client, err);
      });
  });
};
<commit_msg>change twitch messages ws uri<commit_after>'use strict';
const moment = require('moment');
require('moment-timezone');

module.exports = function TwitchMessages(client) {
  const modChannel = client.channels.get('252275732628242432') || client.channels.get('373924698075037706');
  if (!modChannel) {
    client.utils.ownerError('twitchMessages', client, 'Unable to find Mod Channel');
    return;
  }
  const streamInfoSocket = require('socket.io-client')('wss://info.dbkynd.com');
  streamInfoSocket.on('connect', () => {
    client.logger.info('connected to streamInfo websocket');
  });
  streamInfoSocket.on('disconnect', () => {
    client.logger.warn('disconnected from streamInfo websocket');
  });
  streamInfoSocket.on('discord_ban_event', async data => {
    client.logger.debug(data);
    if (!data) return;
    if (typeof data !== 'object') return;
    if (Array.isArray(data)) return;
    if (!modChannel) return;
    client.logger.debug('discord_ban_event received');
    const messages = data.messages
      .sort(x => -parseInt(x.userstate['tmi-sent-ts']))
      .map(x => {
        const time = moment(parseInt(x.userstate['tmi-sent-ts']));
        return `\`\`[${time.tz('America/Los_Angeles').format('MM/DD/YY HH:mm:ss')}]\`\` ${x.message}`;
      });
    const embed = new client.Discord.MessageEmbed()
      .setAuthor(data.banee, await client.twitch.getUserLogo(data.banee_id),
        `https://www.twitch.tv/${data.banee.toLowerCase()}`)
      .setColor('DARK_ORANGE')
      .setDescription(messages.join('\n'))
      .setFooter(`Banned by ${data.banear}`)
      .setTimestamp(new Date(data.time));
    if (data.reason) embed.addField('Ban Reason:', data.reason);
    if (!['SEND_MESSAGES', 'EMBED_LINKS'].every(perm => modChannel.permissionsFor(client.user).has(perm))) {
      client.utils.ownerError('twitchMessages', client, 'Missing Channel Permissions');
      return;
    }
    modChannel.send({ embed })
      .catch(err => {
        client.utils.ownerError('twitchMessages', client, err);
      });
  });

  streamInfoSocket.on('discord_unban_event', async data => {
    client.logger.debug(data);
    if (!data) return;
    if (typeof data !== 'object') return;
    if (Array.isArray(data)) return;
    if (!modChannel) return;
    client.logger.debug('discord_unban_event received');
    const embed = new client.Discord.MessageEmbed()
      .setAuthor(data.banee, await client.twitch.getUserLogo(data.banee_id),
        `https://www.twitch.tv/${data.banee.toLowerCase()}`)
      .setColor('DARK_BLUE')
      .setFooter(`Unbanned by ${data.banear}`)
      .setTimestamp(new Date(data.time));
    if (!['SEND_MESSAGES', 'EMBED_LINKS'].every(perm => modChannel.permissionsFor(client.user).has(perm))) {
      client.utils.ownerError('twitchMessages', client, 'Missing Channel Permissions');
      return;
    }
    modChannel.send({ embed })
      .catch(err => {
        client.utils.ownerError('twitchMessages', client, err);
      });
  });
};
<|endoftext|>


<commit_before>
/*
 *
 * poloniex-unofficial
 * https://git.io/polonode
 *
 * Yet another unofficial Node.js wrapper for the Poloniex cryptocurrency
 * exchange APIs.
 *
 * Copyright (c) 2016 Tyler Filla
 *
 * This software may be modified and distributed under the terms of the MIT
 * license. See the LICENSE file for details.
 *
 */

/*
 * NOTICE: This file needs documentation revisions.
 */

// Localize wrappers
var PushWrapper = module.parent.exports.PushWrapper;
var PublicWrapper = module.parent.exports.PublicWrapper;

// Do not continue without these wrappers
if (!PushWrapper || !PublicWrapper) {
    throw "Failed to localize wrappers (OrderBook.js should not be require()'d externally)";
}

// Default size of update buffer
const DEFAULT_UPDATE_updateBuffer_SIZE = 5;

/*
 * Order book utility constructor.
 */
function OrderBook(currencyPair) {
    this._currencyPair = currencyPair;

    this._updateBufferSize = DEFAULT_UPDATE_updateBuffer_SIZE;

    this._wrapperPush = new PushWrapper();
    this._wrapperPublic = new PublicWrapper();

    this._running = false;

    this._synchronized = false;
    this._synchronizing = false;

    this._asks = null;
    this._bids = null;

    this._lastSeq = -2;

    this._updateBuffer = new Array();

    this._callbackSetStart = new Array();
    this._callbackSetStop = new Array();
    this._callbackSetSyncBegin = new Array();
    this._callbackSetSyncComplete = new Array();
    this._callbackSetSyncLost = new Array();
    this._callbackSetUpdate = new Array();
}

/*
 *
 * function getCurrencyPair()
 *
 * Get the target currency pair.
 *
 */
OrderBook.prototype.getCurrencyPair = function() {
    return this._currencyPair;
};

/*
 *
 * function setCurrencyPair(currencyPair)
 *
 * Set the target currency pair.
 *
 */
OrderBook.prototype.setCurrencyPair = function(currencyPair) {
    // Lock while running
    if (this._running) {
        throw "Currency pair cannot be changed while running";
    }

    this._currencyPair = currencyPair;
};

/*
 *
 * function getUpdateBufferSize()
 *
 * Get the update buffer size.
 *
 */
OrderBook.prototype.getUpdateBufferSize = function() {
    return this._updateBufferSize;
};

/*
 *
 * function setUpdateBufferSize(updateBufferSize)
 *
 * Set the update buffer size.
 *
 */
OrderBook.prototype.setUpdateBufferSize = function(updateBufferSize) {
    this._updateBufferSize = updateBufferSize;
};

/*
 *
 * function getWrapperPush()
 *
 * Get the push wrapper instance.
 *
 */
OrderBook.prototype.getWrapperPush = function() {
    return this._wrapperPush;
};

/*
 *
 * function setWrapperPush(wrapperPush)
 *
 * Set the push wrapper instance.
 *
 */
OrderBook.prototype.setWrapperPush = function(wrapperPush) {
    // Lock while running
    if (this._running) {
        throw "Push wrapper instance cannot be changed while running";
    }

    // Sanity check
    if (!(wrapperPush instanceof PushWrapper)) {
        throw new TypeError("wrapperPush is not an instance of PushWrapper");
    }

    this._wrapperPush = wrapperPush;
};

/*
 *
 * function getWrapperPublic()
 *
 * Get the public wrapper instance.
 *
 */
OrderBook.prototype.getWrapperPublic = function() {
    return this._wrapperPublic;
};

/*
 *
 * function setWrapperPublic(wrapperPublic)
 *
 * Set the public wrapper instance.
 *
 */
OrderBook.prototype.setWrapperPublic = function(wrapperPublic) {
    // Lock while running
    if (this._running) {
        throw "Public wrapper instance cannot be changed while running";
    }

    // Sanity check
    if (!(wrapperPublic instanceof PublicWrapper)) {
        throw new TypeError("wrapperPublic is not an instance of PublicWrapper");
    }

    this._wrapperPublic = wrapperPublic;
};

/*
 *
 * function isRunning()
 *
 * Get whether the tracker is currently running (between start and stop calls).
 *
 */
OrderBook.prototype.isRunning = function() {
    return this._running;
};

/*
 *
 * function isSynchronized()
 *
 * Get whether the tracker has synchronized push and public APIs.
 *
 */
OrderBook.prototype.isSynchronized = function() {
    return this._synchronized;
};

/*
 *
 * function isSynchronizing()
 *
 * Get whether the tracker is currently synchronizing push and public APIs.
 *
 */
OrderBook.prototype.isSynchronizing = function() {
    return this._synchronizing;
};

/*
 *
 * function start()
 *
 * Start tracking the target currency pair's order book.
 *
 */
OrderBook.prototype.start = function() {
    // Sanity check
    if (this._running) {
        throw "Attempt to start, but already running";
    }

    // Ensure wrappers are supplied
    if (!this._wrapperPush || !this._wrapperPublic) {
        throw "Push and/or public wrapper instance(s) not supplied";
    }

    // Start listening to the push API
    this._wrapperPush.orderTrade(this._currencyPair, (err, response) => {
        // Disconnect as soon as running flag is cleared
        if (!this._running) {
            return true;
        }

        // If an error occurred
        if (err) {
            throw "Push wrapper: " + err.msg;
        }

        // Buffer update
        this._bufferUpdate(response);
    });

    // Set running flag
    this._running = true;

    // Notify onStart callbacks
    for (var i = 0; i < this._callbackSetStart.length; i++) {
        this._callbackSetStart[i]();
    }
};

/*
 *
 * function stop()
 *
 * Stop tracking the target currency pair's order book.
 *
 */
OrderBook.prototype.stop = function() {
    // Sanity check
    if (!this._running) {
        throw "Attempt to stop, but not running";
    }

    // Clear running flag
    this._running = false;

    // Notify onStop callbacks
    for (var i = 0; i < this._callbackSetStop.length; i++) {
        this._callbackSetStop[i]();
    }
};

/*
 *
 * function onStart(callback)
 *
 * Register a callback to receive start events.
 *
 */
OrderBook.prototype.onStart = function(callback) {
    // Push to start callback set
    this._callbackSetStart.push(callback);

    // Give user the option to remove it
    return {
        "remove": () => {
            // Remove from start callback set
            this._callbackSetStart.splice(this._callbackSetStart.indexOf(callback), 1);
        }
    };
};

/*
 *
 * function onStop(callback)
 *
 * Register a callback to receive stop events.
 *
 */
OrderBook.prototype.onStop = function(callback) {
    // Push to stop callback set
    this._callbackSetStop.push(callback);

    // Give user the option to remove it
    return {
        "remove": () => {
            // Remove from stop callback set
            this._callbackSetStop.splice(this._callbackSetStop.indexOf(callback), 1);
        }
    };
};

/*
 *
 * function onSyncBegin(callback)
 *
 * Register a callback to receive sync begin events.
 *
 */
OrderBook.prototype.onSyncBegin = function(callback) {
    // Push to sync begin callback set
    this._callbackSetSyncBegin.push(callback);

    // Give user the option to remove it
    return {
        "remove": () => {
            // Remove from sync begin callback set
            this._callbackSetSyncBegin.splice(this._callbackSetSyncBegin.indexOf(callback), 1);
        }
    };
};

/*
 *
 * function onSyncComplete(callback)
 *
 * Register a callback to receive sync complete events.
 *
 */
OrderBook.prototype.onSyncComplete = function(callback) {
    // Push to sync begin callback set
    this._callbackSetSyncComplete.push(callback);

    // Give user the option to remove it
    return {
        "remove": () => {
            // Remove from sync complete callback set
            this._callbackSetSyncComplete.splice(this._callbackSetSyncComplete.indexOf(callback), 1);
        }
    };
};

/*
 *
 * function onSyncLost(callback)
 *
 * Register a callback to receive sync lost events.
 *
 */
OrderBook.prototype.onSyncLost = function(callback) {
    // Push to sync lost callback set
    this._callbackSetSyncLost.push(callback);

    // Give user the option to remove it
    return {
        "remove": () => {
            // Remove from sync lost callback set
            this._callbackSetSyncLost.splice(this._callbackSetSyncLost.indexOf(callback), 1);
        }
    };
};

/*
 *
 * function onUpdate(callback)
 *
 * Register a callback to receive update events.
 *
 */
OrderBook.prototype.onUpdate = function(callback) {
    // Push to update callback set
    this._callbackSetUpdate.push(callback);

    // Give user the option to remove it
    return {
        "remove": () => {
            // Remove from update callback set
            this._callbackSetUpdate.splice(this._callbackSetUpdate.indexOf(callback), 1);
        }
    };
};

/*
 * Internal function to buffer order book updates and handle overflow.
 */
OrderBook.prototype._bufferUpdate = function(update) {
    if (this._updateBuffer.length < this._updateBufferSize) {
        // Add new update to buffer
        this._updateBuffer.push(update);
    } else {
        // Oldest update from the buffer and its accompanying seq number
        var oldestUpdate = null;
        var oldestUpdateIdx = -1;
        var oldestUpdateSeq = -1;

        // Select the oldest update from the buffer
        for (var i = 0; i < this._updateBuffer.length; i++) {
            if (oldestUpdateSeq == -1 || this._updateBuffer[i].seq < oldestUpdateSeq) {
                oldestUpdate = this._updateBuffer[i];
                oldestUpdateIdx = i;
                oldestUpdateSeq = this._updateBuffer[i].seq;
            }
        }

        // If oldest update exists
        if (oldestUpdate) {
            // Replace oldest update with new update
            this._updateBuffer[oldestUpdateIdx] = update;

            // Handle the displaced oldest update
            this._handleUpdate(oldestUpdate);

            // Search for and handle pending consecutive updates (to stay up to date in case of inactivity)
            for (var seq = oldestUpdateSeq + 1; seq <= oldestUpdateSeq + this._updateBuffer.length; seq++) {
                // Whether or not an update(s) with this seq number was found
                var matched = false;

                // Search through update buffer for this seq number
                for (var i = 0; i < this._updateBuffer.length; i++) {
                    // Get this update
                    var update = this._updateBuffer[i];

                    // If seq matches
                    if (this._updateBuffer[i].seq == seq) {
                        // Set matched flag
                        matched = true;

                        // Handle the update
                        this._handleUpdate(update);
                    }
                }

                // Stop searching for consecutive updates if no match was found
                if (!matched) {
                    break;
                }
            }
        } else {
            // Handle new update directly
            this._handleUpdate(update);
        }
    }
};

/*
 * Internal function to handle buffered order book updates.
 */
OrderBook.prototype._handleUpdate = function(update) {
    // Store seq for future comparison
    this._lastSeq = update.seq;

    // If not yet synchronized or currently synchronizing
    if (!this._synchronized || this._synchronizing) {
        // If not currently synchronizing
        if (!this._synchronizing) {
            // Set synchronizing flag
            this._synchronizing = true;

            // Notify onSyncBegin callbacks
            for (var i = 0; i < this._callbackSetSyncBegin.length; i++) {
                this._callbackSetSyncBegin[i]();
            }

            // Request full snapshot of order book from public API (well, hopefully full!)
            this._wrapperPublic.returnOrderBook(this._currencyPair, 999999999, (err, response) => {
                // If this market is frozen
                if (response.isFrozen == "1") {
                    throw "Market for " + update.currencyPair + " is frozen";
                }

                // Store seq from snapshot
                this._lastSeq = response.seq;

                // Reset order book data
                this._asks = new Array();
                this._bids = new Array();

                // Store data from snapshot
                for (var i = 0; i < response.asks.length; i++) {
                    this._asks.push({
                        "rate": response.asks[i][0],
                        "amount": response.asks[i][1]
                    });
                }
                for (var i = 0; i < response.bids.length; i++) {
                    this._bids.push({
                        "rate": response.bids[i][0],
                        "amount": response.bids[i][1]
                    });
                }

                // Set synchronized flag and clear synchronizing flag
                this._synchronized = true;
                this._synchronizing = false;

                // Notify onSyncComplete callbacks
                for (var i = 0; i < this._callbackSetSyncComplete.length; i++) {
                    this._callbackSetSyncComplete[i]();
                }
            });
        }

        // Wait for next update to begin tracking updates
        return;
    }

    // If this update's seq is greater than, but not equal or 1 higher than the last update's seq
    if (update.seq > this._lastSeq && update.seq != this._lastSeq && update.seq != this._lastSeq + 1) {
        // Consider this a loss of synchronization
        this._synchronized = false;

        // Notify onSyncLost callbacks
        for (var i = 0; i < this._callbackSetSyncLost.length; i++) {
            this._callbackSetSyncLost[i]();
        }

        // Wait for next update to begin synchronization
        return;
    }

    // Handle update
    switch (update.updateType) {
    case "orderBookModify":
        // Update amount of appropriate table
        if (update.type == "ask") {
            // Whether or not the rate is already listed
            var rateExists = false;

            // Modify existing amount if rate exists
            for (var i = 0; i < this._asks.length; i++) {
                if (this._asks[i].rate == update.rate) {
                    this._asks[i].amount = update.amount;
                    rateExists = true;
                }
            }

            // If rate doesn't already exist
            if (!rateExists) {
                // Add it
                this._asks.push({
                    "rate": update.rate,
                    "amount": update.amount
                });

                // Sort asks ascending by rateExists
                this._asks.sort((a, b) => {
                    return parseFloat(a.rate) - parseFloat(b.rate);
                });
            }
        } else if (update.type == "bid") {
            // Whether or not the rate is already listed
            var rateExists = false;

            // Modify existing amount if rate exists
            for (var i = 0; i < this._bids.length; i++) {
                if (this._bids[i].rate == update.rate) {
                    this._bids[i].amount = update.amount;
                    rateExists = true;
                }
            }

            // If rate doesn't already exist
            if (!rateExists) {
                // Add it
                this._bids.push({
                    "rate": update.rate,
                    "amount": update.amount
                });

                // Sort bids decending by rate
                this._bids.sort((a, b) => {
                    return parseFloat(b.rate) - parseFloat(a.rate);
                });
            }
        }
        break;
    case "orderBookRemove":
        // Remove row from appropriate table
        if (update.type == "ask") {
            // Remove existing value from ask table
            for (var i = 0; i < this._asks.length; i++) {
                if (this._asks[i].rate == update.rate) {
                    this._asks.splice(i, 1);
                    break;
                }
            }
        } else if (update.type == "bid") {
            // Remove existing value from bid table
            for (var i = 0; i < this._bids.length; i++) {
                if (this._bids[i].rate == update.rate) {
                    this._bids.splice(i, 1);
                    break;
                }
            }
        }
        break;
    }

    // Notify onUpdate callbacks
    for (var i = 0; i < this._callbackSetUpdate.length; i++) {
        this._callbackSetUpdate[i]();
    }
};

module.exports = OrderBook;
<commit_msg>Optimizations<commit_after>
/*
 *
 * poloniex-unofficial
 * https://git.io/polonode
 *
 * Yet another unofficial Node.js wrapper for the Poloniex cryptocurrency
 * exchange APIs.
 *
 * Copyright (c) 2016 Tyler Filla
 *
 * This software may be modified and distributed under the terms of the MIT
 * license. See the LICENSE file for details.
 *
 */

/*
 * NOTICE: This file needs documentation revisions.
 */

// Localize wrappers
var PushWrapper = module.parent.exports.PushWrapper;
var PublicWrapper = module.parent.exports.PublicWrapper;

// Do not continue without these wrappers
if (!PushWrapper || !PublicWrapper) {
    throw "Failed to localize wrappers (OrderBook.js should not be require()'d externally)";
}

// Default size of update buffer
const DEFAULT_UPDATE_updateBuffer_SIZE = 5;

/*
 * Order book utility constructor.
 */
function OrderBook(currencyPair) {
    this._currencyPair = currencyPair;

    this._updateBufferSize = DEFAULT_UPDATE_updateBuffer_SIZE;

    this._wrapperPush = new PushWrapper();
    this._wrapperPublic = new PublicWrapper();

    this._running = false;

    this._synchronized = false;
    this._synchronizing = false;

    this._asks = null;
    this._bids = null;

    this._lastSeq = -2;

    this._updateBuffer = new Array();

    this._callbackSetStart = new Array();
    this._callbackSetStop = new Array();
    this._callbackSetSyncBegin = new Array();
    this._callbackSetSyncComplete = new Array();
    this._callbackSetSyncLost = new Array();
    this._callbackSetUpdate = new Array();
}

/*
 *
 * function getCurrencyPair()
 *
 * Get the target currency pair.
 *
 */
OrderBook.prototype.getCurrencyPair = function() {
    return this._currencyPair;
};

/*
 *
 * function setCurrencyPair(currencyPair)
 *
 * Set the target currency pair.
 *
 */
OrderBook.prototype.setCurrencyPair = function(currencyPair) {
    // Lock while running
    if (this._running) {
        throw "Currency pair cannot be changed while running";
    }

    this._currencyPair = currencyPair;
};

/*
 *
 * function getUpdateBufferSize()
 *
 * Get the update buffer size.
 *
 */
OrderBook.prototype.getUpdateBufferSize = function() {
    return this._updateBufferSize;
};

/*
 *
 * function setUpdateBufferSize(updateBufferSize)
 *
 * Set the update buffer size.
 *
 */
OrderBook.prototype.setUpdateBufferSize = function(updateBufferSize) {
    this._updateBufferSize = updateBufferSize;
};

/*
 *
 * function getWrapperPush()
 *
 * Get the push wrapper instance.
 *
 */
OrderBook.prototype.getWrapperPush = function() {
    return this._wrapperPush;
};

/*
 *
 * function setWrapperPush(wrapperPush)
 *
 * Set the push wrapper instance.
 *
 */
OrderBook.prototype.setWrapperPush = function(wrapperPush) {
    // Lock while running
    if (this._running) {
        throw "Push wrapper instance cannot be changed while running";
    }

    // Sanity check
    if (!(wrapperPush instanceof PushWrapper)) {
        throw new TypeError("wrapperPush is not an instance of PushWrapper");
    }

    this._wrapperPush = wrapperPush;
};

/*
 *
 * function getWrapperPublic()
 *
 * Get the public wrapper instance.
 *
 */
OrderBook.prototype.getWrapperPublic = function() {
    return this._wrapperPublic;
};

/*
 *
 * function setWrapperPublic(wrapperPublic)
 *
 * Set the public wrapper instance.
 *
 */
OrderBook.prototype.setWrapperPublic = function(wrapperPublic) {
    // Lock while running
    if (this._running) {
        throw "Public wrapper instance cannot be changed while running";
    }

    // Sanity check
    if (!(wrapperPublic instanceof PublicWrapper)) {
        throw new TypeError("wrapperPublic is not an instance of PublicWrapper");
    }

    this._wrapperPublic = wrapperPublic;
};

/*
 *
 * function isRunning()
 *
 * Get whether the tracker is currently running (between start and stop calls).
 *
 */
OrderBook.prototype.isRunning = function() {
    return this._running;
};

/*
 *
 * function isSynchronized()
 *
 * Get whether the tracker has synchronized push and public APIs.
 *
 */
OrderBook.prototype.isSynchronized = function() {
    return this._synchronized;
};

/*
 *
 * function isSynchronizing()
 *
 * Get whether the tracker is currently synchronizing push and public APIs.
 *
 */
OrderBook.prototype.isSynchronizing = function() {
    return this._synchronizing;
};

/*
 *
 * function start()
 *
 * Start tracking the target currency pair's order book.
 *
 */
OrderBook.prototype.start = function() {
    // Sanity check
    if (this._running) {
        throw "Attempt to start, but already running";
    }

    // Ensure wrappers are supplied
    if (!this._wrapperPush || !this._wrapperPublic) {
        throw "Push and/or public wrapper instance(s) not supplied";
    }

    // Start listening to the push API
    this._wrapperPush.orderTrade(this._currencyPair, (err, response) => {
        // Disconnect as soon as running flag is cleared
        if (!this._running) {
            return true;
        }

        // If an error occurred
        if (err) {
            throw "Push wrapper: " + err.msg;
        }

        // Buffer update
        this._bufferUpdate(response);
    });

    // Set running flag
    this._running = true;

    // Notify onStart callbacks
    for (var i = 0; i < this._callbackSetStart.length; i++) {
        this._callbackSetStart[i]();
    }
};

/*
 *
 * function stop()
 *
 * Stop tracking the target currency pair's order book.
 *
 */
OrderBook.prototype.stop = function() {
    // Sanity check
    if (!this._running) {
        throw "Attempt to stop, but not running";
    }

    // Clear running flag
    this._running = false;

    // Notify onStop callbacks
    for (var i = 0; i < this._callbackSetStop.length; i++) {
        this._callbackSetStop[i]();
    }
};

/*
 *
 * function onStart(callback)
 *
 * Register a callback to receive start events.
 *
 */
OrderBook.prototype.onStart = function(callback) {
    // Push to start callback set
    this._callbackSetStart.push(callback);

    // Give user the option to remove it
    return {
        "remove": () => {
            // Remove from start callback set
            this._callbackSetStart.splice(this._callbackSetStart.indexOf(callback), 1);
        }
    };
};

/*
 *
 * function onStop(callback)
 *
 * Register a callback to receive stop events.
 *
 */
OrderBook.prototype.onStop = function(callback) {
    // Push to stop callback set
    this._callbackSetStop.push(callback);

    // Give user the option to remove it
    return {
        "remove": () => {
            // Remove from stop callback set
            this._callbackSetStop.splice(this._callbackSetStop.indexOf(callback), 1);
        }
    };
};

/*
 *
 * function onSyncBegin(callback)
 *
 * Register a callback to receive sync begin events.
 *
 */
OrderBook.prototype.onSyncBegin = function(callback) {
    // Push to sync begin callback set
    this._callbackSetSyncBegin.push(callback);

    // Give user the option to remove it
    return {
        "remove": () => {
            // Remove from sync begin callback set
            this._callbackSetSyncBegin.splice(this._callbackSetSyncBegin.indexOf(callback), 1);
        }
    };
};

/*
 *
 * function onSyncComplete(callback)
 *
 * Register a callback to receive sync complete events.
 *
 */
OrderBook.prototype.onSyncComplete = function(callback) {
    // Push to sync begin callback set
    this._callbackSetSyncComplete.push(callback);

    // Give user the option to remove it
    return {
        "remove": () => {
            // Remove from sync complete callback set
            this._callbackSetSyncComplete.splice(this._callbackSetSyncComplete.indexOf(callback), 1);
        }
    };
};

/*
 *
 * function onSyncLost(callback)
 *
 * Register a callback to receive sync lost events.
 *
 */
OrderBook.prototype.onSyncLost = function(callback) {
    // Push to sync lost callback set
    this._callbackSetSyncLost.push(callback);

    // Give user the option to remove it
    return {
        "remove": () => {
            // Remove from sync lost callback set
            this._callbackSetSyncLost.splice(this._callbackSetSyncLost.indexOf(callback), 1);
        }
    };
};

/*
 *
 * function onUpdate(callback)
 *
 * Register a callback to receive update events.
 *
 */
OrderBook.prototype.onUpdate = function(callback) {
    // Push to update callback set
    this._callbackSetUpdate.push(callback);

    // Give user the option to remove it
    return {
        "remove": () => {
            // Remove from update callback set
            this._callbackSetUpdate.splice(this._callbackSetUpdate.indexOf(callback), 1);
        }
    };
};

/*
 * Internal function to buffer order book updates and handle overflow.
 */
OrderBook.prototype._bufferUpdate = function(update) {
    if (this._updateBuffer.length < this._updateBufferSize) {
        // Add new update to buffer
        this._updateBuffer.push(update);
    } else {
        // Oldest update from the buffer and its accompanying seq number
        var oldestUpdate = null;
        var oldestUpdateIdx = -1;
        var oldestUpdateSeq = -1;

        // Select the oldest update from the buffer
        for (var i = 0; i < this._updateBuffer.length; i++) {
            if (oldestUpdateSeq == -1 || this._updateBuffer[i].seq < oldestUpdateSeq) {
                oldestUpdate = this._updateBuffer[i];
                oldestUpdateIdx = i;
                oldestUpdateSeq = this._updateBuffer[i].seq;
            }
        }

        // If oldest update exists
        if (oldestUpdate) {
            // Replace oldest update with new update
            this._updateBuffer[oldestUpdateIdx] = update;

            // Handle the displaced oldest update
            this._handleUpdate(oldestUpdate);

            // Search for and handle pending consecutive updates (to stay up to date in case of inactivity)
            for (var seq = oldestUpdateSeq + 1; seq <= oldestUpdateSeq + this._updateBuffer.length; seq++) {
                // Whether or not an update(s) with this seq number was found
                var matched = false;

                // Search through update buffer for this seq number
                for (var i = 0; i < this._updateBuffer.length; i++) {
                    // Get this update
                    var update = this._updateBuffer[i];

                    // If seq matches
                    if (this._updateBuffer[i].seq == seq) {
                        // Set matched flag
                        matched = true;

                        // Handle the update
                        this._handleUpdate(update);
                    }
                }

                // Stop searching for consecutive updates if no match was found
                if (!matched) {
                    break;
                }
            }
        } else {
            // Handle new update directly
            this._handleUpdate(update);
        }
    }
};

/*
 * Internal function to handle buffered order book updates.
 */
OrderBook.prototype._handleUpdate = function(update) {
    // Store seq for future comparison
    this._lastSeq = update.seq;

    // If not yet synchronized or currently synchronizing
    if (!this._synchronized || this._synchronizing) {
        // If not currently synchronizing
        if (!this._synchronizing) {
            // Set synchronizing flag
            this._synchronizing = true;

            // Notify onSyncBegin callbacks
            for (var i = 0; i < this._callbackSetSyncBegin.length; i++) {
                this._callbackSetSyncBegin[i]();
            }

            // Request full snapshot of order book from public API (well, hopefully full!)
            this._wrapperPublic.returnOrderBook(this._currencyPair, 999999999, (err, response) => {
                // If this market is frozen
                if (response.isFrozen == "1") {
                    throw "Market for " + update.currencyPair + " is frozen";
                }

                // Store seq from snapshot
                this._lastSeq = response.seq;

                // Reset order book tables
                this._asks = new Array();
                this._bids = new Array();

                // Copy asks
                for (var i = 0; i < response.asks.length; i++) {
                    this._asks.push({
                        "rate": parseFloat(response.asks[i][0]),
                        "amount": parseFloat(response.asks[i][1])
                    });
                }

                // Sort asks ascending by rate
                this._asks.sort((a, b) => {
                    return a.rate - b.rate;
                });

                // Copy bids
                for (var i = 0; i < response.bids.length; i++) {
                    // Add row to bids table
                    this._bids.push({
                        "rate": parseFloat(response.bids[i][0]),
                        "amount": parseFloat(response.bids[i][1])
                    });
                }

                // Sort bids descending by rate
                this._asks.sort((a, b) => {
                    return b.rate - a.rate;
                });

                // Synchronized; set flags accordingly
                this._synchronized = true;
                this._synchronizing = false;

                // Notify onSyncComplete callbacks
                for (var i = 0; i < this._callbackSetSyncComplete.length; i++) {
                    this._callbackSetSyncComplete[i]();
                }
            });
        }

        // Wait for next update to begin tracking updates
        return;
    }

    // If this update's seq is greater than, but not equal or 1 higher than the last update's seq
    if (update.seq > this._lastSeq && update.seq != this._lastSeq && update.seq != this._lastSeq + 1) {
        // Consider this a loss of synchronization
        this._synchronized = false;

        // Notify onSyncLost callbacks
        for (var i = 0; i < this._callbackSetSyncLost.length; i++) {
            this._callbackSetSyncLost[i]();
        }

        // Wait for next update to begin synchronization
        return;
    }

    // Handle update
    switch (update.updateType) {
    case "orderBookModify":
        // Apply update to appropriate table
        if (update.type == "ask") {
            // Modify bids table
            this._modifyTable(this._asks, update);

            // Sort asks ascending by rate
            this._asks.sort((a, b) => {
                return a.rate - b.rate;
            });
        } else if (update.type == "bid") {
            // Modify bids table
            this._modifyTable(this._bids, update);

            // Sort bids decending by rate
            this._bids.sort((a, b) => {
                return b.rate - a.rate;
            });
        }
        break;
    case "orderBookRemove":
        // Remove row from appropriate table
        if (update.type == "ask") {
            // Remove existing value from ask table
            for (var i = 0; i < this._asks.length; i++) {
                if (this._asks[i].rate == update.rate) {
                    this._asks.splice(i, 1);
                    break;
                }
            }
        } else if (update.type == "bid") {
            // Remove existing value from bid table
            for (var i = 0; i < this._bids.length; i++) {
                if (this._bids[i].rate == update.rate) {
                    this._bids.splice(i, 1);
                    break;
                }
            }
        }
        break;
    }

    // Notify onUpdate callbacks
    for (var i = 0; i < this._callbackSetUpdate.length; i++) {
        this._callbackSetUpdate[i]();
    }
};

/*
 * Internal function to modify a particular table with an update.
 */
OrderBook.prototype._modifyTable = function(table, update) {
    // Iterate over table
    for (var i = 0; i < table.length; i++) {
        // If this row's rate equals the update's rate
        if (table[i].rate == update.rate) {
            // Update this row
            table[i].amount = update.amount;

            return;
        }
    }

    // Rate isn't already listed, so add it
    table.push({
        "rate": parseFloat(update.rate),
        "amount": parseFloat(update.amount)
    });
};

module.exports = OrderBook;
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import AxiomError from 'axiom/core/error';
import Path from 'axiom/fs/path';

import {getWhitespace} from 'wash/string_utils';

/** @typedef JsExecuteContext$$module$axiom$fs$js$execute_context */
var JsExecuteContext;

/** @typedef FileSystemManager$$module$axiom$fs$base$file_system_manager */
var FileSystemManager;

/**
 * @param {JsExecuteContext} cx
 * @return {void}
 */
export var main = function(cx) {
  cx.ready();

  if (cx.getArg('help') || cx.getArg('_')) {
    cx.stdout.write([
      'usage: mount [-t|--type <type>] [-n|--name <name>]',
      'List mounted filesystems, or mount a new file system.',
      '',
      'If called with no arguments this command will list the current mounts.',
      'If the -t argument is provided, this will defer to a mount.<type>',
      'executable to mount a new file system.',
      '',
      'If -n is provided, it\'s passed to the mount command.'
    ].join('\r\n') + '\r\n');
    cx.closeOk();
    return;
  }

  if (cx.getArg('t')) {
    mountFileSystem_(cx);
  } else {
    listFileSystems_(cx);
  }
};

/**
 * @param {JsExecuteContext} cx
 * @return {void}
 */
var listFileSystems_ = function(cx) {
  /** @type {FileSystemManager} */
  var fsm = cx.fileSystemManager;
  var fileSystems = fsm.getFileSystems();

  var rv = 'Mounted file systems:\n';
  var maxLength = 0;
  fileSystems.forEach(function(fileSystem) {
    if (fileSystem.rootPath.spec.length >= maxLength)
      maxLength = fileSystem.rootPath.spec.length;
  });

  fileSystems.forEach(function(fileSystem) {
    var spaces = getWhitespace(maxLength - fileSystem.rootPath.spec.length + 3);
    rv += fileSystem.rootPath.spec + spaces + '"' +
        fileSystem.description + '"' + '\n';
  });

  cx.stdout.write(rv);
  cx.closeOk(null);
};

/**
 * @param {JsExecuteContext} cx
 * @return {void}
 */
var mountFileSystem_ = function(cx) {
  /** @type {string} */
  var fsType = cx.getArg('t');
  var fsMountCmd = new Path('jsfs:/exe/mount.' + fsType);

  var arg = {};
  var name = cx.getArg('name', null);
  if (name)
    arg['name'] = name;

  cx.call(fsMountCmd, arg).then(function() {
    cx.closeOk();
  }).catch(function(err) {
    cx.closeError(err);
  });
};

main.signature = {
  'help|h': '?',
  'type|t': '$',
  'name|n': '$',
  '_': '@'
};

export default main;
<commit_msg>Pass '_' arguments to sub-mount commands.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import AxiomError from 'axiom/core/error';
import Path from 'axiom/fs/path';

import {getWhitespace} from 'wash/string_utils';

/** @typedef JsExecuteContext$$module$axiom$fs$js$execute_context */
var JsExecuteContext;

/** @typedef FileSystemManager$$module$axiom$fs$base$file_system_manager */
var FileSystemManager;

/**
 * @param {JsExecuteContext} cx
 * @return {void}
 */
export var main = function(cx) {
  cx.ready();

  if (cx.getArg('help')) {
    cx.stdout.write([
      'usage: mount [-t|--type <type>] [-n|--name <name>] [values]',
      'List mounted filesystems, or mount a new file system.',
      '',
      'If called with no arguments this command will list the current mounts.',
      '',
      'If the -t argument is provided, this will defer to a mount.<type>',
      'executable to mount a new file system.',
      '',
      'If -n is provided, it\'s passed to the mount.<type> command.',
      '',
      'If additional [values] are provided, they are passed to the',
      'mount.<type> command.',
    ].join('\r\n') + '\r\n');
    cx.closeOk();
    return;
  }

  if (cx.getArg('t')) {
    mountFileSystem_(cx);
  } else {
    listFileSystems_(cx);
  }
};

/**
 * @param {JsExecuteContext} cx
 * @return {void}
 */
var listFileSystems_ = function(cx) {
  /** @type {FileSystemManager} */
  var fsm = cx.fileSystemManager;
  var fileSystems = fsm.getFileSystems();

  var rv = 'Mounted file systems:\n';
  var maxLength = 0;
  fileSystems.forEach(function(fileSystem) {
    if (fileSystem.rootPath.spec.length >= maxLength)
      maxLength = fileSystem.rootPath.spec.length;
  });

  fileSystems.forEach(function(fileSystem) {
    var spaces = getWhitespace(maxLength - fileSystem.rootPath.spec.length + 3);
    rv += fileSystem.rootPath.spec + spaces + '"' +
        fileSystem.description + '"' + '\n';
  });

  cx.stdout.write(rv);
  cx.closeOk(null);
};

/**
 * @param {JsExecuteContext} cx
 * @return {void}
 */
var mountFileSystem_ = function(cx) {
  /** @type {string} */
  var fsType = cx.getArg('t');
  var fsMountCmd = new Path('jsfs:/exe/mount.' + fsType);

  var arg = {};
  var name = cx.getArg('name', null);
  if (name)
    arg['name'] = name;
  var values = cx.getArg('_', null);
  if (values)
    arg['_'] = values;

  cx.call(fsMountCmd, arg).then(function() {
    cx.closeOk();
  }).catch(function(err) {
    cx.closeError(err);
  });
};

main.signature = {
  'help|h': '?',
  'type|t': '$',
  'name|n': '$',
  '_': '@'
};

export default main;
<|endoftext|>


<commit_before>/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
*/

var service=require('cordova/plugin/webos/service'),
    cordova = require('cordova');

module.exports = {
    id: "webos",
    initialize: function() {
        var modulemapper = require('cordova/modulemapper');

        modulemapper.loadMatchingModules(/cordova.*\/symbols$/);
        modulemapper.mapModules(window);

        if (window.PalmSystem) {
            window.PalmSystem.stageReady();
        }

        var Mojo = window.Mojo || {};

        // wait for deviceready before listening and firing document events
        document.addEventListener("deviceready", function () {

            // LunaSysMgr calls this when the windows is maximized or opened.
            window.Mojo.stageActivated = function() {
                console.log("stageActivated");
                cordova.fireDocumentEvent("resume");
            };
            // LunaSysMgr calls this when the windows is minimized or closed.
            window.Mojo.stageDeactivated = function() {
                console.log("stageDeactivated");
                cordova.fireDocumentEvent("pause");
            };
            // LunaSysMgr calls this when a KeepAlive app's window is hidden
            window.Mojo.hide = function() {
                console.log("hide");
            };
            // LunaSysMgr calls this when a KeepAlive app's window is shown
            window.Mojo.show = function() {
                console.log("show");
            };

            // LunaSysMgr calls this whenever an app is "launched;"
            window.Mojo.relaunch = function() {
                // need to return true to tell sysmgr the relaunch succeeded.
                // otherwise, it'll try to focus the app, which will focus the first
                // opened window of an app with multiple windows.

                var lp=JSON.parse(PalmSystem.launchParams) || {};

                if (lp['palm-command'] && lp['palm-command'] == 'open-app-menu') {
                    console.log("event:ToggleAppMenu");
                    cordova.fireDocumentEvent("menubutton");
                }

                console.log("relaunch");
                return true;
            };

            // start to listen for network connection changes
            service.Request('palm://com.palm.connectionmanager', {
                method: 'getstatus',
                parameters: { subscribe: true },
                onSuccess: function (result) {
                    console.log("subscribe:result:"+JSON.stringify(result));

                    if (!result.isInternetConnectionAvailable) {
                        if (navigator.onLine) {
                            console.log("Firing event:offline");
                            cordova.fireDocumentEvent("offline");
                        }
                    } else {
                        console.log("Firing event:online");
                        cordova.fireDocumentEvent("online");
                    }
                },
                onFailure: function(e) {
                    console.error("subscribe:error");
                }
            });

        });
    },
    merges: {
        navigator: {
            children: {
                service: {
                    path: "cordova/plugin/webos/service"
                },
                application: {
                    path: "cordova/plugin/webos/application"
                },
                window: {
                    path: "cordova/plugin/webos/window"
                },
                notification: {
                    path: "cordova/plugin/webos/notification"
                },
                orientation: {
                    path: "cordova/plugin/webos/orientation"
                },
                keyboard: {
                    path: "cordova/plugin/webos/keyboard"
                }
            }
        }
    }
};
<commit_msg>Update lib/webos/platform.js<commit_after>/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
*/

var service=require('cordova/plugin/webos/service'),
    cordova = require('cordova');

module.exports = {
    id: "webos",
    initialize: function() {
        var modulemapper = require('cordova/modulemapper');

        modulemapper.loadMatchingModules(/cordova.*\/symbols$/);
        modulemapper.mapModules(window);

        if (window.PalmSystem) {
            window.PalmSystem.stageReady();
        }

        // create global Mojo object if it does not exist
        Mojo = window.Mojo || {};

        // wait for deviceready before listening and firing document events
        document.addEventListener("deviceready", function () {

            // LunaSysMgr calls this when the windows is maximized or opened.
            window.Mojo.stageActivated = function() {
                console.log("stageActivated");
                cordova.fireDocumentEvent("resume");
            };
            // LunaSysMgr calls this when the windows is minimized or closed.
            window.Mojo.stageDeactivated = function() {
                console.log("stageDeactivated");
                cordova.fireDocumentEvent("pause");
            };
            // LunaSysMgr calls this when a KeepAlive app's window is hidden
            window.Mojo.hide = function() {
                console.log("hide");
            };
            // LunaSysMgr calls this when a KeepAlive app's window is shown
            window.Mojo.show = function() {
                console.log("show");
            };

            // LunaSysMgr calls this whenever an app is "launched;"
            window.Mojo.relaunch = function() {
                // need to return true to tell sysmgr the relaunch succeeded.
                // otherwise, it'll try to focus the app, which will focus the first
                // opened window of an app with multiple windows.

                var lp=JSON.parse(PalmSystem.launchParams) || {};

                if (lp['palm-command'] && lp['palm-command'] == 'open-app-menu') {
                    console.log("event:ToggleAppMenu");
                    cordova.fireDocumentEvent("menubutton");
                }

                console.log("relaunch");
                return true;
            };

            // start to listen for network connection changes
            service.Request('palm://com.palm.connectionmanager', {
                method: 'getstatus',
                parameters: { subscribe: true },
                onSuccess: function (result) {
                    console.log("subscribe:result:"+JSON.stringify(result));

                    if (!result.isInternetConnectionAvailable) {
                        if (navigator.onLine) {
                            console.log("Firing event:offline");
                            cordova.fireDocumentEvent("offline");
                        }
                    } else {
                        console.log("Firing event:online");
                        cordova.fireDocumentEvent("online");
                    }
                },
                onFailure: function(e) {
                    console.error("subscribe:error");
                }
            });

        });
    },
    merges: {
        navigator: {
            children: {
                service: {
                    path: "cordova/plugin/webos/service"
                },
                application: {
                    path: "cordova/plugin/webos/application"
                },
                window: {
                    path: "cordova/plugin/webos/window"
                },
                notification: {
                    path: "cordova/plugin/webos/notification"
                },
                orientation: {
                    path: "cordova/plugin/webos/orientation"
                },
                keyboard: {
                    path: "cordova/plugin/webos/keyboard"
                }
            }
        }
    }
};
<|endoftext|>