<commit_before>(function() {
  var HAL = {
    Models: {},
    Views: {},
    currentDocument: {}
  };

  HAL.client = function(opts) {
    this.vent = opts.vent;
    this.get = function(url) {
      var self = this;
      this.vent.trigger('location-change', { url: url });
      var jqxhr = $.ajax({
        url: url,
        dataType: 'json',
        headers: this.headers(),
        success: function(resource, textStatus, jqXHR) {
          self.vent.trigger('response', {
            resource: resource,
            headers: jqXHR.getAllResponseHeaders() });
        }
      }).error(function() {
        self.vent.trigger('fail-response', { jqxhr: jqxhr });
      });
    };

    this.headers = function() {
      HAL.Helpers.getHeaders($('#request-headers'));
    };
  };

  HAL.Router = Backbone.Router.extend({
    initialize: function(opts) {
      var self = this;
      opts = opts || {};

      var vent = _.extend({}, Backbone.Events);

      vent.bind('response', function(e) {
        window.HAL.currentDocument = e.resource || {};
      });

      this.client = new HAL.client({ vent: vent });

      $.ajaxSetup({ headers: { 'Accept': 'application/hal+json, application/json, */*; q=0.01' } });

      this.browser = new HAL.Views.Browser({ el: $('#browser'), vent: vent });
      this.inspectorView = new HAL.Views.Inspector({ el: $('#inspector'), vent: vent });

      if (window.location.hash === '') {
        var entry = opts.entryPoint || '/';
        window.location.hash = entry;
      }
    },

    routes: {
      '*url': 'resourceRoute'
    },

    resourceRoute: function(url) {
      url = location.hash.slice(1);
      if (url.slice(0,8) !== 'NON-GET:') {
        this.client.get(url);
      }
    }
  });

  HAL.Helpers.getHeaders = function($input) {
    var header_lines = $input.val().split("\n");
    var headers = {};
    _.each(header_lines, function(line) {
      var parts = line.split(':');
      if (parts.length == 2) {
        var name = parts[0].trim();
        var value = parts[1].trim();
        headers[name] = value;
      }
    });
    return headers;
  };

  HAL.Models.Resource = Backbone.Model.extend({
    initialize: function(representation) {
      this.links = representation._links;
      if(representation._embedded !== undefined) {
        this.embeddedResources = this.buildEmbeddedResources(representation._embedded);
      }
      this.set(representation);
      this.unset('_embedded', { silent: true });
      this.unset('_links', { silent: true });
    },

    buildEmbeddedResources: function(embeddedResources) {
      var result = {};
      _.each(embeddedResources, function(obj, rel) {
        if($.isArray(obj)) {
          var arr = [];
          _.each(obj, function(resource, i) {
            var newResource = new HAL.Models.Resource(resource);
            newResource.identifier = rel + '[' + i + ']';
            arr.push(newResource);
          });
          result[rel] = arr;
        } else {
          var newResource = new HAL.Models.Resource(obj);
          newResource.identifier = rel;
          result[rel] = newResource;
        }
      });
      return result;
    }
  });

  HAL.Views.Browser = Backbone.View.extend({
    initialize: function(opts) {
      var self = this;
      this.vent = opts.vent;
      this.locationBar = new HAL.Views.LocationBar({ el: this.$('#location-bar'), vent: this.vent });
      this.resourceView = new HAL.Views.Resource({ el: this.$('#current-resource'), vent: this.vent });
    }
  });

  HAL.Views.Resource = Backbone.View.extend({
    initialize: function(opts) {
      var self = this;
      this.vent = opts.vent;
      _.bindAll(this, 'followLink');
      _.bindAll(this, 'showNonSafeRequestDialog');
      _.bindAll(this, 'showUriQueryDialog');
      _.bindAll(this, 'showDocs');
      this.vent.bind('response', function(e) {
        self.render(new HAL.Models.Resource(e.resource));
      });
      this.vent.bind('fail-response', function(e) {
        self.vent.trigger('response', { resource: null });
        self.showFailedRequest(e.jqxhr);
      });
    },

    events: {
      'click .links a.follow': 'followLink',
      'click .links a.non-get': 'showNonSafeRequestDialog',
      'click .links a.query': 'showUriQueryDialog',
      'click .links a.dox': 'showDocs'
    },

    render: function(resource) {
      this.$el.html(this.template({
        state: resource.toJSON(),
        links: resource.links
      }));
      var $embres = this.$('.embedded-resources');
      $embres.html(this.renderEmbeddedResources(resource.embeddedResources));
      $embres.accordion();
      return this;
    },

    showFailedRequest: function(jqxhr) {
      this.$el.html(this.failedRequestTemplate({ jqxhr: jqxhr }));
    },

    followLink: function(e) {
      e.preventDefault();
      var $target = $(e.target);
      var uri = $target.attr('href') || $target.parent().attr('href');
      window.location.hash = uri;
    },

    showUriQueryDialog: function(e) {
      e.preventDefault();

      var $target = $(e.target);
      var uri = $target.attr('href') || $target.parent().attr('href');

      var d = new HAL.Views.QueryUriDialog({
        href: uri
      }).render();

      d.$el.dialog({
        title: 'Query URI Template',
        width: 400
      });
      window.foo = d;
    },

    showNonSafeRequestDialog: function(e) {
      e.preventDefault();

      var d = new HAL.Views.NonSafeRequestDialog({
        href: $(e.target).attr('href'),
        vent: this.vent
      }).render();

      d.$el.dialog({
        title: 'Non Safe Request',
        width: 500
      });
    },

    showDocs: function(e) {
      e.preventDefault();
      var $target = $(e.target);
      var uri = $target.attr('href') || $target.parent().attr('href');
      this.vent.trigger('show-docs', { url: uri });
    },

    renderEmbeddedResources: function(embeddedResources) {
      var self = this;
      var result = '';
      _.each(embeddedResources, function(obj) {
        if ($.isArray(obj)) {
          _.each(obj, function(resource) {
            result += self.embeddedResourceTemplate({
              state: resource.toJSON(),
              links: resource.links,
              name: resource.identifier
            });
          });
        } else {
          result += self.embeddedResourceTemplate({
            state: obj.toJSON(),
            links: obj.links,
            name: obj.identifier
          });
        }
      });
      return result;
    },

    template: _.template($('#resource-template').html()),

    failedRequestTemplate: _.template($('#failed-request-template').html()),

    embeddedResourceTemplate: _.template($('#embedded-resource-template').html())
  });

  HAL.Views.LocationBar = Backbone.View.extend({
    initialize: function(opts) {
      var self = this;
      this.vent = opts.vent;
      this.vent.bind('location-change', function(e) {
        self.setLocation(e.url);
      });
    },

    setLocation: function(url) {
      this.address.html(url);
    },

    address: $('.address')
  });

  HAL.Views.Inspector = Backbone.View.extend({
    initialize: function(opts) {
      this.vent = opts.vent;
      _.bindAll(this, 'showDocs');
      _.bindAll(this, 'showRawResource');
      this.vent.bind('show-docs', this.showDocs);
      this.vent.bind('response', this.showRawResource);
    },

    showDocs: function(e) {
      this.$('.panel').html('');
    },

    showRawResource: function(e) {
      this.$('.panel').html('
' + JSON.stringify(e.resource, null, 2) + '
');
    }
  });

  HAL.Views.QueryUriDialog = Backbone.View.extend({
    initialize: function(opts) {
      this.href = opts.href;
      this.uriTemplate = uritemplate(this.href);
      _.bindAll(this, 'submitQuery');
      _.bindAll(this, 'renderPreview');
    },

    events: {
      'submit form': 'submitQuery',
      'keyup textarea': 'renderPreview',
      'change textarea': 'renderPreview'
    },

    submitQuery: function(e) {
      e.preventDefault();
      var input;
      try {
        input = JSON.parse(this.$('textarea').val());
      } catch(err) {
        input = {};
      }
      this.$el.dialog('close');
      window.location.hash = this.uriTemplate.expand(input);
    },

    renderPreview: function(e) {
      var input, result;
      try {
        input = JSON.parse($(e.target).val());
        result = this.uriTemplate.expand(input);
      } catch (err) {
        result = 'Invalid json input';
      }
      this.$('.preview').html(result);
    },

    render: function() {
      this.$el.html(this.template({ href: this.href }));
      this.$('textarea').trigger('keyup');
      return this;
    },

    template: _.template($('#query-uri-template').html())
  });

  HAL.Views.NonSafeRequestDialog = Backbone.View.extend({
    initialize: function(opts) {
      this.href = opts.href;
      this.vent = opts.vent;
      this.uriTemplate = uritemplate(this.href);
      _.bindAll(this, 'submitQuery');
    },

    events: {
      'submit form': 'submitQuery'
    },

    headers: function() {
      HAL.Helpers.getHeaders(this.$('.headers'));
    },

    submitQuery: function(e) {
      e.preventDefault();
      var self = this;
      var headers = this.headers();
      var method = this.$('.method').val();
      var body = this.$('.body').val();
      var jqxhr = $.ajax({
        url: this.href,
        dataType: 'json',
        type: method,
        headers: headers,
        data: body
      }).done(function(response) {
        self.vent.trigger('response', { resource: response });
      }).fail(function(response) {
        self.vent.trigger('fail-response', { jqxhr: jqxhr });
      }).always(function() {
        self.vent.trigger('location-change', { url: self.href });
        window.location.hash = 'NON-GET:' + self.href;
      });
      this.$el.dialog('close');
    },

    render: function() {
      this.$el.html(this.template({ href: this.href, user_defined_headers: $('#request-headers').val() }));
      return this;
    },

    template: _.template($('#non-safe-request-template').html())
  });

  var urlRegex = /(http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;

  HAL.isUrl = function(str) {
    return str.match(urlRegex) || isCurie(str);
  };

  HAL.truncateIfUrl = function(str) {
    var replaceRegex = /(http|https):\/\/([^\/]*)\//;
    return str.replace(replaceRegex, '.../');
  };

  var isCurie = function(string) {
    return string.split(':').length > 1;
  };

  HAL.buildUrl = function(rel) {
    if (!rel.match(urlRegex) && isCurie(rel) && HAL.currentDocument._links.curie) {
      var tmpl = uritemplate(HAL.currentDocument._links.curie.href);
      return tmpl.expand({ rel: rel.split(':')[1] });
    } else {
      return rel;
    }
  };

  window.HAL = HAL;
})();
<commit_msg>Further refactoring, to match the style of the code<commit_after>(function() {
  var HAL = {
    Models: {},
    Views: {},
    currentDocument: {}
  };

  HAL.client = function(opts) {
    this.vent = opts.vent;
    this.get = function(url) {
      var self = this;
      this.vent.trigger('location-change', { url: url });
      var jqxhr = $.ajax({
        url: url,
        dataType: 'json',
        headers: this.headers(),
        success: function(resource, textStatus, jqXHR) {
          self.vent.trigger('response', {
            resource: resource,
            headers: jqXHR.getAllResponseHeaders() });
        }
      }).error(function() {
        self.vent.trigger('fail-response', { jqxhr: jqxhr });
      });
    };

    this.headers = function() {
      HAL.parseHeaders($('#request-headers').val());
    };
  };

  HAL.Router = Backbone.Router.extend({
    initialize: function(opts) {
      var self = this;
      opts = opts || {};

      var vent = _.extend({}, Backbone.Events);

      vent.bind('response', function(e) {
        window.HAL.currentDocument = e.resource || {};
      });

      this.client = new HAL.client({ vent: vent });

      $.ajaxSetup({ headers: { 'Accept': 'application/hal+json, application/json, */*; q=0.01' } });

      this.browser = new HAL.Views.Browser({ el: $('#browser'), vent: vent });
      this.inspectorView = new HAL.Views.Inspector({ el: $('#inspector'), vent: vent });

      if (window.location.hash === '') {
        var entry = opts.entryPoint || '/';
        window.location.hash = entry;
      }
    },

    routes: {
      '*url': 'resourceRoute'
    },

    resourceRoute: function(url) {
      url = location.hash.slice(1);
      if (url.slice(0,8) !== 'NON-GET:') {
        this.client.get(url);
      }
    }
  });

  HAL.Models.Resource = Backbone.Model.extend({
    initialize: function(representation) {
      this.links = representation._links;
      if(representation._embedded !== undefined) {
        this.embeddedResources = this.buildEmbeddedResources(representation._embedded);
      }
      this.set(representation);
      this.unset('_embedded', { silent: true });
      this.unset('_links', { silent: true });
    },

    buildEmbeddedResources: function(embeddedResources) {
      var result = {};
      _.each(embeddedResources, function(obj, rel) {
        if($.isArray(obj)) {
          var arr = [];
          _.each(obj, function(resource, i) {
            var newResource = new HAL.Models.Resource(resource);
            newResource.identifier = rel + '[' + i + ']';
            arr.push(newResource);
          });
          result[rel] = arr;
        } else {
          var newResource = new HAL.Models.Resource(obj);
          newResource.identifier = rel;
          result[rel] = newResource;
        }
      });
      return result;
    }
  });

  HAL.Views.Browser = Backbone.View.extend({
    initialize: function(opts) {
      var self = this;
      this.vent = opts.vent;
      this.locationBar = new HAL.Views.LocationBar({ el: this.$('#location-bar'), vent: this.vent });
      this.resourceView = new HAL.Views.Resource({ el: this.$('#current-resource'), vent: this.vent });
    }
  });

  HAL.Views.Resource = Backbone.View.extend({
    initialize: function(opts) {
      var self = this;
      this.vent = opts.vent;
      _.bindAll(this, 'followLink');
      _.bindAll(this, 'showNonSafeRequestDialog');
      _.bindAll(this, 'showUriQueryDialog');
      _.bindAll(this, 'showDocs');
      this.vent.bind('response', function(e) {
        self.render(new HAL.Models.Resource(e.resource));
      });
      this.vent.bind('fail-response', function(e) {
        self.vent.trigger('response', { resource: null });
        self.showFailedRequest(e.jqxhr);
      });
    },

    events: {
      'click .links a.follow': 'followLink',
      'click .links a.non-get': 'showNonSafeRequestDialog',
      'click .links a.query': 'showUriQueryDialog',
      'click .links a.dox': 'showDocs'
    },

    render: function(resource) {
      this.$el.html(this.template({
        state: resource.toJSON(),
        links: resource.links
      }));
      var $embres = this.$('.embedded-resources');
      $embres.html(this.renderEmbeddedResources(resource.embeddedResources));
      $embres.accordion();
      return this;
    },

    showFailedRequest: function(jqxhr) {
      this.$el.html(this.failedRequestTemplate({ jqxhr: jqxhr }));
    },

    followLink: function(e) {
      e.preventDefault();
      var $target = $(e.target);
      var uri = $target.attr('href') || $target.parent().attr('href');
      window.location.hash = uri;
    },

    showUriQueryDialog: function(e) {
      e.preventDefault();

      var $target = $(e.target);
      var uri = $target.attr('href') || $target.parent().attr('href');

      var d = new HAL.Views.QueryUriDialog({
        href: uri
      }).render();

      d.$el.dialog({
        title: 'Query URI Template',
        width: 400
      });
      window.foo = d;
    },

    showNonSafeRequestDialog: function(e) {
      e.preventDefault();

      var d = new HAL.Views.NonSafeRequestDialog({
        href: $(e.target).attr('href'),
        vent: this.vent
      }).render();

      d.$el.dialog({
        title: 'Non Safe Request',
        width: 500
      });
    },

    showDocs: function(e) {
      e.preventDefault();
      var $target = $(e.target);
      var uri = $target.attr('href') || $target.parent().attr('href');
      this.vent.trigger('show-docs', { url: uri });
    },

    renderEmbeddedResources: function(embeddedResources) {
      var self = this;
      var result = '';
      _.each(embeddedResources, function(obj) {
        if ($.isArray(obj)) {
          _.each(obj, function(resource) {
            result += self.embeddedResourceTemplate({
              state: resource.toJSON(),
              links: resource.links,
              name: resource.identifier
            });
          });
        } else {
          result += self.embeddedResourceTemplate({
            state: obj.toJSON(),
            links: obj.links,
            name: obj.identifier
          });
        }
      });
      return result;
    },

    template: _.template($('#resource-template').html()),

    failedRequestTemplate: _.template($('#failed-request-template').html()),

    embeddedResourceTemplate: _.template($('#embedded-resource-template').html())
  });

  HAL.Views.LocationBar = Backbone.View.extend({
    initialize: function(opts) {
      var self = this;
      this.vent = opts.vent;
      this.vent.bind('location-change', function(e) {
        self.setLocation(e.url);
      });
    },

    setLocation: function(url) {
      this.address.html(url);
    },

    address: $('.address')
  });

  HAL.Views.Inspector = Backbone.View.extend({
    initialize: function(opts) {
      this.vent = opts.vent;
      _.bindAll(this, 'showDocs');
      _.bindAll(this, 'showRawResource');
      this.vent.bind('show-docs', this.showDocs);
      this.vent.bind('response', this.showRawResource);
    },

    showDocs: function(e) {
      this.$('.panel').html('');
    },

    showRawResource: function(e) {
      this.$('.panel').html('
' + JSON.stringify(e.resource, null, 2) + '
');
    }
  });

  HAL.Views.QueryUriDialog = Backbone.View.extend({
    initialize: function(opts) {
      this.href = opts.href;
      this.uriTemplate = uritemplate(this.href);
      _.bindAll(this, 'submitQuery');
      _.bindAll(this, 'renderPreview');
    },

    events: {
      'submit form': 'submitQuery',
      'keyup textarea': 'renderPreview',
      'change textarea': 'renderPreview'
    },

    submitQuery: function(e) {
      e.preventDefault();
      var input;
      try {
        input = JSON.parse(this.$('textarea').val());
      } catch(err) {
        input = {};
      }
      this.$el.dialog('close');
      window.location.hash = this.uriTemplate.expand(input);
    },

    renderPreview: function(e) {
      var input, result;
      try {
        input = JSON.parse($(e.target).val());
        result = this.uriTemplate.expand(input);
      } catch (err) {
        result = 'Invalid json input';
      }
      this.$('.preview').html(result);
    },

    render: function() {
      this.$el.html(this.template({ href: this.href }));
      this.$('textarea').trigger('keyup');
      return this;
    },

    template: _.template($('#query-uri-template').html())
  });

  HAL.Views.NonSafeRequestDialog = Backbone.View.extend({
    initialize: function(opts) {
      this.href = opts.href;
      this.vent = opts.vent;
      this.uriTemplate = uritemplate(this.href);
      _.bindAll(this, 'submitQuery');
    },

    events: {
      'submit form': 'submitQuery'
    },

    headers: function() {
      HAL.parseHeaders(this.$('.headers').val());
    },

    submitQuery: function(e) {
      e.preventDefault();
      var self = this;
      var headers = this.headers();
      var method = this.$('.method').val();
      var body = this.$('.body').val();
      var jqxhr = $.ajax({
        url: this.href,
        dataType: 'json',
        type: method,
        headers: headers,
        data: body
      }).done(function(response) {
        self.vent.trigger('response', { resource: response });
      }).fail(function(response) {
        self.vent.trigger('fail-response', { jqxhr: jqxhr });
      }).always(function() {
        self.vent.trigger('location-change', { url: self.href });
        window.location.hash = 'NON-GET:' + self.href;
      });
      this.$el.dialog('close');
    },

    render: function() {
      this.$el.html(this.template({ href: this.href, user_defined_headers: $('#request-headers').val() }));
      return this;
    },

    template: _.template($('#non-safe-request-template').html())
  });

  var urlRegex = /(http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;

  HAL.isUrl = function(str) {
    return str.match(urlRegex) || isCurie(str);
  };

  HAL.truncateIfUrl = function(str) {
    var replaceRegex = /(http|https):\/\/([^\/]*)\//;
    return str.replace(replaceRegex, '.../');
  };

  var isCurie = function(string) {
    return string.split(':').length > 1;
  };

  HAL.buildUrl = function(rel) {
    if (!rel.match(urlRegex) && isCurie(rel) && HAL.currentDocument._links.curie) {
      var tmpl = uritemplate(HAL.currentDocument._links.curie.href);
      return tmpl.expand({ rel: rel.split(':')[1] });
    } else {
      return rel;
    }
  };

  HAL.parseHeaders = function(string) {
    var header_lines = string.split("\n");
    var headers = {};
    _.each(header_lines, function(line) {
      var parts = line.split(':');
      if (parts.length == 2) {
        var name = parts[0].trim();
        var value = parts[1].trim();
        headers[name] = value;
      }
    });
    return headers;
  };

  window.HAL = HAL;
})();
<|endoftext|>


<commit_before>module.exports = VerticesToVerticesPipe;

var BasePipe = require('../basePipe'),
    createFilter = require('../utils/filterExpression'),
    createEmptyIterator = require('../iterators/emptyIterator'),
    createEdgeIterator = require('../iterators/edgeIterator'),
    util = require('util');

util.inherits(VerticesToVerticesPipe, BasePipe);

function VerticesToVerticesPipe(graph, mode, filter) {
  if (!(this instanceof VerticesToVerticesPipe)) {
    return new VerticesToVerticesPipe(graph, mode, filter);
  }
  BasePipe.call(this);

  var customFilter;
  if (typeof filter !== 'undefined') {
    customFilter = createFilter(filter);
  } else {
    customFilter = function () { return true; }
  }

  this._currentEdgesIterator = createEmptyIterator();
  this._graph = graph;
  if (mode === 'out') {
    this._linkFilter = outNodeFilter;
    this._getNode = getOutNode;
  } else if (mode === 'in') {
    this._linkFilter = inNodeFilter;
    this._getNode = getInNode;
  } else if (mode === 'both') {
    this._linkFilter = bothNodeFilter;
    this._getNode = getOtherNode;
  } else {
    throw new Error("Unsupported mode of VerticesToVerticesPipe. Expected (out|in|both), got: " + mode);
  }

  function outNodeFilter(link, nodeId) {
    return link.toId !== nodeId && customFilter(link);
  }

  function getOutNode(link) {
    var node = graph.getNode(link.toId);
    if (node) {
      return node;
    }
    throw new Error("Edge link points to removed node");
  }

  function inNodeFilter(link, nodeId) {
    return link.fromId !== nodeId && customFilter(link);
  }

  function getInNode(link) {
    var node = graph.getNode(link.fromId);
    if (node) {
      return node;
    }
    throw new Error("Edge link starts at removed node");
  }

  function bothNodeFilter(link, nodeId) {
    return customFilter(link);
  }

  function getOtherNode(link, nodeId) {
    var otherNodeId = link.fromId === nodeId ? link.toId : link.fromId;
    var node = graph.getNode(otherNodeId);
    if (node) {
      return node;
    }
    throw new Error("Edge link starts or ends at removed node");
  }
}

VerticesToVerticesPipe.prototype._moveNext = function () {
  while (true) {
    if (this._currentEdgesIterator.moveNext()) {
      // we have neighbor node which matches search criteria. Get it:
      var edge = this._currentEdgesIterator.current();
      var currentVertex = this._sourcePipe.current();
      this._current = this._getNode(edge, currentVertex.id);
      return true;
    } else if (this._sourcePipe.moveNext()) {
      // there is no more edges for the current node. Let's move forward to next node.
      this._currentEdgesIterator = createEdgeIterator(this._sourcePipe.current(), this._linkFilter);
      // next iteration of the outter loop will either return matching edge
      // or take next vertex or result in false response for _moveNext()
    } else {
      // there is no nodes to start from left
      return false;
    }
  }
};
<commit_msg>Updated vertices to vertices doc<commit_after>/**
 * # Vertices to Vertices pipe
 *
 * This pipe take a vertex as an input, and emits adjacent vertices (neighbors)
 * as an output.
 */
module.exports = VerticesToVerticesPipe;

var BasePipe = require('../basePipe'),
    createFilter = require('../utils/filterExpression'),
    createEmptyIterator = require('../iterators/emptyIterator'),
    createEdgeIterator = require('../iterators/edgeIterator'),
    util = require('util');

util.inherits(VerticesToVerticesPipe, BasePipe);

/**
 * Depending on `mode` emitted vertices are:
 *
 * * `out` - emits vertices connected with outgoing edge (out adjacent)
 * * `in` - emits vertices connected with incoming edge (in adjacent)
 * * `both` - emits both `in` and `out` adjacent vertices
 *
 * See [Syntactic Sugar](../pipeSugar.html) for more examples;
 *
 * Results can be filtered based on edge attributes with `filter` attribute.
 * See [Filtering Pipes](../utils/filterExpression.html).
 */
function VerticesToVerticesPipe(graph, mode, filter) {
  if (!(this instanceof VerticesToVerticesPipe)) {
    return new VerticesToVerticesPipe(graph, mode, filter);
  }

  BasePipe.call(this);

  var customFilter;
  if (typeof filter !== 'undefined') {
    customFilter = createFilter(filter);
  } else {
    customFilter = function () { return true; }
  }

  this._currentEdgesIterator = createEmptyIterator();
  this._graph = graph;
  if (mode === 'out') {
    this._linkFilter = outNodeFilter;
    this._getNode = getOutNode;
  } else if (mode === 'in') {
    this._linkFilter = inNodeFilter;
    this._getNode = getInNode;
  } else if (mode === 'both') {
    this._linkFilter = bothNodeFilter;
    this._getNode = getOtherNode;
  } else {
    throw new Error("Unsupported mode of VerticesToVerticesPipe. Expected (out|in|both), got: " + mode);
  }

  function outNodeFilter(link, nodeId) {
    return link.toId !== nodeId && customFilter(link);
  }

  function getOutNode(link) {
    var node = graph.getNode(link.toId);
    if (node) {
      return node;
    }
    throw new Error("Edge link points to removed node");
  }

  function inNodeFilter(link, nodeId) {
    return link.fromId !== nodeId && customFilter(link);
  }

  function getInNode(link) {
    var node = graph.getNode(link.fromId);
    if (node) {
      return node;
    }
    throw new Error("Edge link starts at removed node");
  }

  function bothNodeFilter(link, nodeId) {
    return customFilter(link);
  }

  function getOtherNode(link, nodeId) {
    var otherNodeId = link.fromId === nodeId ? link.toId : link.fromId;
    var node = graph.getNode(otherNodeId);
    if (node) {
      return node;
    }
    throw new Error("Edge link starts or ends at removed node");
  }
}

VerticesToVerticesPipe.prototype._moveNext = function () {
  while (true) {
    if (this._currentEdgesIterator.moveNext()) {
      // We have neighbor node which matches search criteria. Get it:
      var edge = this._currentEdgesIterator.current();
      var currentVertex = this._sourcePipe.current();
      this._current = this._getNode(edge, currentVertex.id);
      return true;
    } else if (this._sourcePipe.moveNext()) {
      // There is no more edges for the current node. Let's move forward to next node.
      this._currentEdgesIterator = createEdgeIterator(this._sourcePipe.current(), this._linkFilter);
      // Next iteration of the outter loop will either return matching edge
      // or take next vertex or result in false response for _moveNext()
    } else {
      // There is no nodes to start from left
      return false;
    }
  }
};
<|endoftext|>


<commit_before>var fs = require('fs'),
    obf = require('../../lib/pub/minify.js');

var result = obf.obfuscate({
    'core.js':['z.js']
},{
    bags:{
        "w":"w"
    },
    obf_level:3,
    code_map:{
        //'e.js':fs.readFileSync('./element.js', "utf8"),
        //'f.js':fs.readFileSync('./json.js', "utf8"),
        'h.js':'(function(){_def = "xxxxxxx";console.log(_def);window._aaaaaaaaaaaa = {\'for\': "htmlFor"};if (!!_aaaaaaaaaaaa.b){ console.log(_aaaaaaaaaaaa); }})();',
        'g.js':'var x = "http://a.b.com/a/a.html";location.href = "http://nei.hz.netease.com/";',
        '2.js':'var x ={},y=\'xxx\'; x[\'__abc\'] = \'xxxx\';console.log(x[y]);e = {7:\'rgb\',\'a-b\':4,__init : 0,__reset : 1,__destroy : 2,__initNode : 3,__doBuild : 4,__onShow : 5,__onHide : 6,__onRefresh : 7}, t = {__supInit : 0,__supReset : 1,__supDestroy : 2,__supInitNode : 3,__supDoBuild : 4,__supOnShow : 5,__supOnHide : 6,__supOnRefresh : 7};',
        '1.js':'HTMLElement.prototype[\'__defineGetter__\']("innerText",function(){return this.textContent;});HTMLElement.prototype[\'__defineSetter__\']("innerText",function(_content){this.textContent = _content;});',
        'a.js':'var a = {}; a.abc = function zzr(zx,zy){zx=1;zy=2;}; function xj(){}; xj();var a = true; var x = {a:"zzzz",v:"vvvvvvvvvvv"};console.log(x.a+":"+x.v);x.b = "mmmmmm"',
        'b.js':'var b = "bbbb"; test: while(true){var dddddddddddd = "xxxxx";}',
        'c.js':'(function(){var ccccccc = "ccccccccc";window.abc=function def(){return ccccccc;};})();',
        'd.js':'(function(){var dddddddddddd = "ddddddddddddddddd";a="zzzzzz";if(DEBUG){var x="xxxxx";}})();',
        'i.js':'var a=1,b=2,c;c=a;b=a;a=c;',
        'z.js':'function u(x) {        var v = [];        (function w(y, z) {            for (var A = y.firstChild; A; A = A.nextSibling) {                if (A.nodeType == 3) {                    z += A.nodeValue.length                } else {                    if (A.nodeType == 1) {                        v.push({                            event: "start",                            offset: z,                            node: A                        });                        z = w(A, z);                        if (!t(A).match(/br|hr|img|input/)) {                            v.push({                                event: "stop",                                offset: z,                                node: A                            })                        }                    }                }            }            return z        })(x, 0);        return v    }'
    }
});

var bags = result.bags;
var test = {};
for(var x in bags){
    if (!!test[bags[x]]){
        console.log(bags[x]+' exist! ');
    }
    test[bags[x]] = !0;
}

fs.writeFileSync('./bags.json',JSON.stringify(result.bags,null,'\t'));
fs.writeFileSync('./code.json',JSON.stringify(result.files,null,'\t'));
fs.writeFileSync('./core.js',result.files['core.js']);

<commit_msg>exclude object property with quote when mangling, e.g.{"_abc":"aaaa"}<commit_after>var fs = require('fs'),
    obf = require('../../lib/pub/minify.js');

var result = obf.obfuscate({
    'core.js':['zz.js']
},{
    bags:{
        "w":"w"
    },
    obf_level:3,
    code_map:{
        'zz.js':'var x = {_abc:"abc","_def":"def","a-b":"aabb"};x["_ghi"] = "gggg";',
        //'e.js':fs.readFileSync('./element.js', "utf8"),
        //'f.js':fs.readFileSync('./json.js', "utf8"),
        'h.js':'(function(){_def = "xxxxxxx";console.log(_def);window._aaaaaaaaaaaa = {\'for\': "htmlFor"};if (!!_aaaaaaaaaaaa.b){ console.log(_aaaaaaaaaaaa); }})();',
        'g.js':'var x = "http://a.b.com/a/a.html";location.href = "http://nei.hz.netease.com/";',
        '2.js':'var x ={},y=\'xxx\'; x[\'__abc\'] = \'xxxx\';console.log(x[y]);e = {7:\'rgb\',\'a-b\':4,__init : 0,__reset : 1,__destroy : 2,__initNode : 3,__doBuild : 4,__onShow : 5,__onHide : 6,__onRefresh : 7}, t = {__supInit : 0,__supReset : 1,__supDestroy : 2,__supInitNode : 3,__supDoBuild : 4,__supOnShow : 5,__supOnHide : 6,__supOnRefresh : 7};',
        '1.js':'HTMLElement.prototype[\'__defineGetter__\']("innerText",function(){return this.textContent;});HTMLElement.prototype[\'__defineSetter__\']("innerText",function(_content){this.textContent = _content;});',
        'a.js':'var a = {}; a.abc = function zzr(zx,zy){zx=1;zy=2;}; function xj(){}; xj();var a = true; var x = {a:"zzzz",v:"vvvvvvvvvvv"};console.log(x.a+":"+x.v);x.b = "mmmmmm"',
        'b.js':'var b = "bbbb"; test: while(true){var dddddddddddd = "xxxxx";}',
        'c.js':'(function(){var ccccccc = "ccccccccc";window.abc=function def(){return ccccccc;};})();',
        'd.js':'(function(){var dddddddddddd = "ddddddddddddddddd";a="zzzzzz";if(DEBUG){var x="xxxxx";}})();',
        'i.js':'var a=1,b=2,c;c=a;b=a;a=c;',
        'z.js':'function u(x) {        var v = [];        (function w(y, z) {            for (var A = y.firstChild; A; A = A.nextSibling) {                if (A.nodeType == 3) {                    z += A.nodeValue.length                } else {                    if (A.nodeType == 1) {                        v.push({                            event: "start",                            offset: z,                            node: A                        });                        z = w(A, z);                        if (!t(A).match(/br|hr|img|input/)) {                            v.push({                                event: "stop",                                offset: z,                                node: A                            })                        }                    }                }            }            return z        })(x, 0);        return v    }'
    }
});

var bags = result.bags;
var test = {};
for(var x in bags){
    if (!!test[bags[x]]){
        console.log(bags[x]+' exist! ');
    }
    test[bags[x]] = !0;
}

fs.writeFileSync('./bags.json',JSON.stringify(result.bags,null,'\t'));
fs.writeFileSync('./code.json',JSON.stringify(result.files,null,'\t'));
fs.writeFileSync('./core.js',result.files['core.js']);

<|endoftext|>


<commit_before>/* Hammer-time - v0.3.0
 * http://github.com/hammerjs/hammer-time
 *
 * Copyright Alexander Schmitz and other contributors
 * Released under the MIT license
 *
 * Expiramental fastclick based on a partial polyfill of
 * touch-action: none; CSS property
 */

( function() {

	// Detect support for necessary features;
	var MO = window.MutationObserver || window.WebKitMutationObserver;
	var touchevents = ( "ontouchstart" in window ) ||
	                  ( window.DocumentTouch && document instanceof DocumentTouch );
	var nativeTouchAction = document.documentElement.style[ "touch-action" ] !== undefined ||
			                            document.documentElement.style[ "-ms-touch-action" ];

// If there is native touch action bail the hammer has already dropped
if ( nativeTouchAction || !touchevents || !MO ) {
	return;
}

//Check if a global Hammer object already exists
window.Hammer = window.Hammer || {};

// We need to save the last touch start in iOS 8 if it is more then 150ms
// it will trigger native fast click which cant ne stoped even with all the might
// of thors hammer and a return false
var touchMatchNone = /touch-action[:][\s]*(none)[^;'"]*/;
var touchMatchManipulation = /touch-action[:][\s]*(manipulation)[^;'"]*/;
var touchMatch = /touch-action/;
var iOS = ( navigator.userAgent.match( /(iPad|iPhone|iPod)/g ) ? true : false );
var gl = ( function() {
	try {
		var canvas = document.createElement( "canvas" );
		return !!( window.WebGLRenderingContext && ( canvas.getContext( "webgl" ) ||
			canvas.getContext( "experimental-webgl" ) ) );
	}
	catch ( e ) { return false; } } )();
var timeTouch = gl && iOS;

window.Hammer.time = {

	// Check if an element has touch action none in its style attribute and thusly should
	// be hammered upon
	getTouchAction: function( element ) {
		return this.checkStyleString( element.getAttribute( "style" ) );
	},
	checkStyleString: function( style ) {
		if ( !touchMatch.test( style ) ) {
			return undefined;
		}
		if ( touchMatchNone.test( style ) ) {
			return "none";
		}
		if ( touchMatchManipulation.test( style ) ) {
			return "manipulation";
		}
		return true;
	},
	shouldHammer: function( e ) {
		var parentAction = this.hasParent( e.target );
		return ( parentAction && ( !timeTouch || Date.now() - e.target.lastStart < 125 ) ) ?
				parentAction : false;
	},
	touchHandler: function( e ) {
		var pos = e.target.getBoundingClientRect();
		var scrolled = pos.top !== this.pos.top || pos.left !== this.pos.left;
		var hammerType = this.shouldHammer( e );

		// Check both if we should trigger fast click and the time to avoid a double trigger with
		// native fast click
		if ( hammerType === "none" ||
					( scrolled === false && hammerType === "manipulation" ) ) {
			if ( e.type === "touchend" ) {
				e.target.focus();

				// Wait for next tic so events fire in proper order
				setTimeout( function() {
					e.target.click();
				}, 0 );
			}

			// Prevent the click which will come after this otherwise but with a 300ms delay
			e.preventDefault();
		}
		this.scrolled = false;
		delete e.target.lastStart;
	},
	touchStart: function( e ) {
		this.pos = e.target.getBoundingClientRect();
		if ( timeTouch && this.hasParent( e.target ) ) {
			e.target.lastStart = Date.now();
		}
	},
	styleWatcher: function( mutations ) {
		mutations.forEach( this.styleUpdater, this );
	},
	styleUpdater: function( mutation ) {

		// We just caused this update bail
		if ( mutation.target.updateNext ) {
			mutation.target.updateNext = false;
			return;
		}

		var touchAction = this.getTouchAction( mutation.target );

		if ( touchAction ) {
			if ( touchAction !== "none" ) {
				mutation.target.hadTouchNone = false;
			}
			return;
		}
		if ( !touchAction &&
				(
					( mutation.oldValue && this.checkStyleString( mutation.oldValue ) ) ||
					mutation.target.hadTouchNone
				)
			) {

			// We save this because durring animations which update the style in quick succession
			// style tag can update quicker then the mutation observer fires so we lose the oldValue
			// property which contains our refrence to the original which contained touch-action.
			mutation.target.hadTouchNone = true;

			// Save the fact that we caused the next update
			mutation.target.updateNext = false;

			// Add touch action back to the style attribute
			mutation.target
				.setAttribute( "style",
					mutation.target.getAttribute( "style" ) + " touch-action: none;"
				);

		}
	},
	hasParent: function( node ) {
		var touchAction;
		for ( var cur = node; cur && cur.parentNode; cur = cur.parentNode ) {
			touchAction = this.getTouchAction( cur );
			if ( touchAction ) {
				return touchAction;
			}
		}
		return false;
	},
	installStartEvents: function() {
		document.addEventListener( "touchstart", this.touchStart.bind( this ) );
		document.addEventListener( "mousedown", this.touchStart.bind( this ) );
	},
	installEndEvents: function() {
		document.addEventListener( "touchend", this.touchHandler.bind( this ), true );
		document.addEventListener( "mouseup", this.touchHandler.bind( this ), true );
	},
	installObserver: function() {

		// We need to observe changes to style attributes because if something updates the style
		// attribute it will remove the touch-action property because browsers santitize the style
		// attribute when its properties are updated.
		this.observer = new MO( this.styleWatcher.bind( this ) ).observe( document, {
			subtree: true,
			attributes: true,
			attributeOldValue: true,
			attributeFilter: [ "style" ]
		} );
	},
	install: function() {
		this.installEndEvents();
		this.installStartEvents();
		this.installObserver();
	}
};

window.Hammer.time.install();

} )();
<commit_msg>dropHammer: add dropHammer method for performance<commit_after>/* Hammer-time - v0.3.0
 * http://github.com/hammerjs/hammer-time
 *
 * Copyright Alexander Schmitz and other contributors
 * Released under the MIT license
 *
 * Expiramental fastclick based on a partial polyfill of
 * touch-action: none; CSS property
 */

( function() {

	// Detect support for necessary features;
	var MO = window.MutationObserver || window.WebKitMutationObserver;
	var touchevents = ( "ontouchstart" in window ) ||
	                  ( window.DocumentTouch && document instanceof DocumentTouch );
	var nativeTouchAction = document.documentElement.style[ "touch-action" ] !== undefined ||
			                            document.documentElement.style[ "-ms-touch-action" ];

// If there is native touch action bail the hammer has already dropped
if ( nativeTouchAction || !touchevents || !MO ) {
	return;
}

//Check if a global Hammer object already exists
window.Hammer = window.Hammer || {};

// We need to save the last touch start in iOS 8 if it is more then 150ms
// it will trigger native fast click which cant ne stoped even with all the might
// of thors hammer and a return false
var touchMatchNone = /touch-action[:][\s]*(none)[^;'"]*/;
var touchMatchManipulation = /touch-action[:][\s]*(manipulation)[^;'"]*/;
var touchMatch = /touch-action/;
var iOS = ( navigator.userAgent.match( /(iPad|iPhone|iPod)/g ) ? true : false );
var gl = ( function() {
	try {
		var canvas = document.createElement( "canvas" );
		return !!( window.WebGLRenderingContext && ( canvas.getContext( "webgl" ) ||
			canvas.getContext( "experimental-webgl" ) ) );
	}
	catch ( e ) { return false; } } )();
var timeTouch = gl && iOS;

window.Hammer.time = {

	// Check if an element has touch action none in its style attribute and thusly should
	// be hammered upon
	getTouchAction: function( element ) {
		return this.checkStyleString( element.getAttribute( "style" ) );
	},
	checkStyleString: function( style ) {
		if ( !touchMatch.test( style ) ) {
			return undefined;
		}
		if ( touchMatchNone.test( style ) ) {
			return "none";
		}
		if ( touchMatchManipulation.test( style ) ) {
			return "manipulation";
		}
		return true;
	},
	shouldHammer: function( e ) {
		var parentAction = e.target.hasParent;
		return ( parentAction && ( !timeTouch || Date.now() - e.target.lastStart < 125 ) ) ?
				parentAction : false;
	},
	touchHandler: function( e ) {
		var hammerType = this.shouldHammer( e );

		// Check both if we should trigger fast click and the time to avoid a double trigger with
		// native fast click
		if ( hammerType === "none" ) {
			this.dropHammer( e );
		} else if ( hammerType === "manipulation" ) {
			var pos = e.target.getBoundingClientRect();
			var scrolled = pos.top !== this.pos.top || pos.left !== this.pos.left;
			!scrolled && this.dropHammer( e );
		}
		this.scrolled = false;
		delete e.target.lastStart;
		delete e.target.hasParent;
	},
	dropHammer: function( e ) {
		if ( e.type === "touchend" ) {
			e.target.focus();

			// Wait for next tic so events fire in proper order
			setTimeout( function() {
				e.target.click();
			}, 0 );
		}

		// Prevent the click which will come after this otherwise but with a 300ms delay
		e.preventDefault();
	},
	touchStart: function( e ) {
		this.pos = e.target.getBoundingClientRect();
		e.target.hasParent = this.hasParent( e.target );
		if ( timeTouch && e.target.hasParent ) {
			e.target.lastStart = Date.now();
		}
	},
	styleWatcher: function( mutations ) {
		mutations.forEach( this.styleUpdater, this );
	},
	styleUpdater: function( mutation ) {

		// We just caused this update bail
		if ( mutation.target.updateNext ) {
			mutation.target.updateNext = false;
			return;
		}

		var touchAction = this.getTouchAction( mutation.target );

		if ( touchAction ) {
			if ( touchAction !== "none" ) {
				mutation.target.hadTouchNone = false;
			}
			return;
		}
		if ( !touchAction &&
				(
					( mutation.oldValue && this.checkStyleString( mutation.oldValue ) ) ||
					mutation.target.hadTouchNone
				)
			) {

			// We save this because during animations which update the style in quick succession
			// style tag can update quicker then the mutation observer fires so we lose the oldValue
			// property which contains our refrence to the original which contained touch-action.
			mutation.target.hadTouchNone = true;

			// Save the fact that we caused the next update
			mutation.target.updateNext = false;

			// Add touch action back to the style attribute
			mutation.target
				.setAttribute( "style",
					mutation.target.getAttribute( "style" ) + " touch-action: none;"
				);

		}
	},
	hasParent: function( node ) {
		var touchAction;
		for ( var cur = node; cur && cur.parentNode; cur = cur.parentNode ) {
			touchAction = this.getTouchAction( cur );
			if ( touchAction ) {
				return touchAction;
			}
		}
		return false;
	},
	installStartEvents: function() {
		document.addEventListener( "touchstart", this.touchStart.bind( this ) );
		document.addEventListener( "mousedown", this.touchStart.bind( this ) );
	},
	installEndEvents: function() {
		document.addEventListener( "touchend", this.touchHandler.bind( this ), true );
		document.addEventListener( "mouseup", this.touchHandler.bind( this ), true );
	},
	installObserver: function() {

		// We need to observe changes to style attributes because if something updates the style
		// attribute it will remove the touch-action property because browsers santitize the style
		// attribute when its properties are updated.
		this.observer = new MO( this.styleWatcher.bind( this ) ).observe( document, {
			subtree: true,
			attributes: true,
			attributeOldValue: true,
			attributeFilter: [ "style" ]
		} );
	},
	install: function() {
		this.installEndEvents();
		this.installStartEvents();
		this.installObserver();
	}
};

window.Hammer.time.install();

} )();
<|endoftext|>


<commit_before>/* global URL, Blob */

var airplay = require('airplay-js')
var chromecasts = require('chromecasts')()
var dragDrop = require('drag-drop')
var electron = require('electron')
var networkAddress = require('network-address')
var path = require('path')
var throttle = require('throttleit')
var torrentPoster = require('./lib/torrent-poster')
var getClient = require('./lib/get-client')

var createElement = require('virtual-dom/create-element')
var diff = require('virtual-dom/diff')
var patch = require('virtual-dom/patch')

var HEADER_HEIGHT = 38

var App = require('./views/app')

var state = global.state = {
  server: null,
  player: null,
  currentPage: {
    type: 'list'
  },
  view: {
    title: 'WebTorrent',
    client: null,
    savedWindowBounds: null,
    history: [],
    historyIndex: 0,
    chromecast: null,
    airplay: null
  }
}

var currentVDom, rootElement, updateThrottled

function init () {
  currentVDom = App(state, dispatch)
  rootElement = createElement(currentVDom)
  document.body.appendChild(rootElement)

  updateThrottled = throttle(update, 250)

  getClient(function (err, client) {
    if (err) return onError(err)
    global.client = client
    state.view.client = client
    client.on('warning', onWarning)
    client.on('error', onError)
  })

  dragDrop('body', onFiles)

  chromecasts.on('update', function (player) {
    state.view.chromecast = player
    update()
  })

  airplay.createBrowser().on('deviceOn', function (player) {
    state.view.airplay = player
  }).start()

  document.addEventListener('paste', function () {
    electron.ipcRenderer.send('addTorrentFromPaste')
  })
}
init()

function update () {
  var newVDom = App(state, dispatch)
  var patches = diff(currentVDom, newVDom)
  rootElement = patch(rootElement, patches)
  currentVDom = newVDom

  updateDockIcon()
}

function updateDockIcon () {
  if (state.view.client) {
    var progress = state.view.client.progress
    // Hide progress bar when client has no torrents, or progress is 100%
    if (state.view.client.torrents.length === 0 || progress === 1) {
      progress = -1
    }
    electron.ipcRenderer.send('setProgress', progress)
  }
}

setInterval(function () {
  update()
}, 5000)

function dispatch (action, ...args) {
  console.log('dispatch: %s %o', action, args)
  if (action === 'addTorrent') {
    addTorrent(args[0] /* torrentId */)
  }
  if (action === 'seed') {
    seed(args[0] /* files */)
  }
  if (action === 'openPlayer') {
    openPlayer(args[0] /* torrent */)
  }
  // if (action === 'closePlayer') {
  //   closePlayer()
  // }
  if (action === 'openChromecast') {
    openChromecast(args[0] /* torrent */)
  }
  if (action === 'openAirplay') {
    openAirplay(args[0] /* torrent */)
  }
  if (action === 'setDimensions') {
    setDimensions(args[0] /* dimensions */)
  }
  if (action === 'back') {
    if (state.player === 'local') {
      restoreBounds()
      closePlayer()
    }
  }
}

electron.ipcRenderer.on('addTorrent', function (e, torrentId) {
  addTorrent(torrentId)
})

electron.ipcRenderer.on('seed', function (e, files) {
  seed(files)
})

function onFiles (files) {
  // .torrent file = start downloading the torrent
  files.filter(isTorrentFile).forEach(function (torrentFile) {
    dispatch('addTorrent', torrentFile)
  })

  // everything else = seed these files
  dispatch('seed', files.filter(isNotTorrentFile))
}

function isTorrentFile (file) {
  var extname = path.extname(file.name).toLowerCase()
  return extname === '.torrent'
}

function isNotTorrentFile (file) {
  return !isTorrentFile(file)
}

function addTorrent (torrentId) {
  getClient(function (err, client) {
    if (err) return onError(err)
    var torrent = client.add(torrentId)
    addTorrentEvents(torrent)
  })
}

function seed (files) {
  if (files.length === 0) return
  getClient(function (err, client) {
    if (err) return onError(err)
    var torrent = client.seed(files)
    addTorrentEvents(torrent)
  })
}

function addTorrentEvents (torrent) {
  torrent.on('infoHash', update)
  torrent.on('done', update)
  torrent.on('download', updateThrottled)
  torrent.on('upload', updateThrottled)
  torrent.on('ready', function () {
    torrentReady(torrent)
  })
  update()
}

function torrentReady (torrent) {
  torrentPoster(torrent, function (err, buf) {
    if (err) return onError(err)
    torrent.posterURL = URL.createObjectURL(new Blob([ buf ], { type: 'image/png' }))
    update()
  })
  update()
}

function startServer (torrent, cb) {
  // use largest file
  var index = torrent.files.indexOf(torrent.files.reduce(function (a, b) {
    return a.length > b.length ? a : b
  }))

  var server = torrent.createServer()
  server.listen(0, function () {
    var port = server.address().port
    var urlSuffix = ':' + port + '/' + index
    state.server = {
      server: server,
      localURL: 'http://localhost' + urlSuffix,
      networkURL: 'http://' + networkAddress() + urlSuffix
    }
    cb()
  })
}

function closeServer () {
  state.server.server.destroy()
  state.server = null
}

function openPlayer (torrent) {
  startServer(torrent, function () {
    state.player = 'local'
    update()
  })
}

function closePlayer () {
  closeServer()
  state.player = null
  update()
}

function openChromecast (torrent) {
  startServer(torrent, function () {
    state.view.chromecast.play(state.server.networkURL, { title: 'WebTorrent — ' + torrent.name })
    state.view.chromecast.on('error', function (err) {
      err.message = 'Chromecast: ' + err.message
      onError(err)
    })
    state.player = 'chromecast'
    update()
  })
}

function openAirplay (torrent) {
  startServer(torrent, function () {
    state.view.airplay.play(state.server.networkURL, 0, function () {})
    // TODO: handle airplay errors
    state.player = 'airplay'
    update()
  })
}

function setDimensions (dimensions) {
  state.view.savedWindowBounds = electron.remote.getCurrentWindow().getBounds()

  // Limit window size to screen size
  var workAreaSize = electron.remote.screen.getPrimaryDisplay().workAreaSize
  var width = Math.min(dimensions.width, workAreaSize.width)
  var height = Math.min(dimensions.height, workAreaSize.height)
  var aspectRatio = width / height

  height += HEADER_HEIGHT

  // Center window on screen
  var x = Math.floor((workAreaSize.width - width) / 2)
  var y = Math.floor((workAreaSize.height - height) / 2)

  electron.ipcRenderer.send('setAspectRatio', aspectRatio, { width: 0, height: HEADER_HEIGHT })
  electron.ipcRenderer.send('setBounds', { x, y, width, height })
}

function restoreBounds () {
  electron.ipcRenderer.send('setAspectRatio', 0)
  electron.ipcRenderer.send('setBounds', state.view.savedWindowBounds, true)
}

function onError (err) {
  console.error(err.stack)
  window.alert(err.message || err)
  update()
}

function onWarning (err) {
  console.log('warning: %s', err.message)
}
<commit_msg>throttled updates -> 1000ms<commit_after>/* global URL, Blob */

var airplay = require('airplay-js')
var chromecasts = require('chromecasts')()
var dragDrop = require('drag-drop')
var electron = require('electron')
var networkAddress = require('network-address')
var path = require('path')
var throttle = require('throttleit')
var torrentPoster = require('./lib/torrent-poster')
var getClient = require('./lib/get-client')

var createElement = require('virtual-dom/create-element')
var diff = require('virtual-dom/diff')
var patch = require('virtual-dom/patch')

var HEADER_HEIGHT = 38

var App = require('./views/app')

var state = global.state = {
  server: null,
  player: null,
  currentPage: {
    type: 'list'
  },
  view: {
    title: 'WebTorrent',
    client: null,
    savedWindowBounds: null,
    history: [],
    historyIndex: 0,
    chromecast: null,
    airplay: null
  }
}

var currentVDom, rootElement, updateThrottled

function init () {
  currentVDom = App(state, dispatch)
  rootElement = createElement(currentVDom)
  document.body.appendChild(rootElement)

  updateThrottled = throttle(update, 1000)

  getClient(function (err, client) {
    if (err) return onError(err)
    global.client = client
    state.view.client = client
    client.on('warning', onWarning)
    client.on('error', onError)
  })

  dragDrop('body', onFiles)

  chromecasts.on('update', function (player) {
    state.view.chromecast = player
    update()
  })

  airplay.createBrowser().on('deviceOn', function (player) {
    state.view.airplay = player
  }).start()

  document.addEventListener('paste', function () {
    electron.ipcRenderer.send('addTorrentFromPaste')
  })
}
init()

function update () {
  var newVDom = App(state, dispatch)
  var patches = diff(currentVDom, newVDom)
  rootElement = patch(rootElement, patches)
  currentVDom = newVDom

  updateDockIcon()
}

function updateDockIcon () {
  if (state.view.client) {
    var progress = state.view.client.progress
    // Hide progress bar when client has no torrents, or progress is 100%
    if (state.view.client.torrents.length === 0 || progress === 1) {
      progress = -1
    }
    electron.ipcRenderer.send('setProgress', progress)
  }
}

setInterval(function () {
  update()
}, 5000)

function dispatch (action, ...args) {
  console.log('dispatch: %s %o', action, args)
  if (action === 'addTorrent') {
    addTorrent(args[0] /* torrentId */)
  }
  if (action === 'seed') {
    seed(args[0] /* files */)
  }
  if (action === 'openPlayer') {
    openPlayer(args[0] /* torrent */)
  }
  // if (action === 'closePlayer') {
  //   closePlayer()
  // }
  if (action === 'openChromecast') {
    openChromecast(args[0] /* torrent */)
  }
  if (action === 'openAirplay') {
    openAirplay(args[0] /* torrent */)
  }
  if (action === 'setDimensions') {
    setDimensions(args[0] /* dimensions */)
  }
  if (action === 'back') {
    if (state.player === 'local') {
      restoreBounds()
      closePlayer()
    }
  }
}

electron.ipcRenderer.on('addTorrent', function (e, torrentId) {
  addTorrent(torrentId)
})

electron.ipcRenderer.on('seed', function (e, files) {
  seed(files)
})

function onFiles (files) {
  // .torrent file = start downloading the torrent
  files.filter(isTorrentFile).forEach(function (torrentFile) {
    dispatch('addTorrent', torrentFile)
  })

  // everything else = seed these files
  dispatch('seed', files.filter(isNotTorrentFile))
}

function isTorrentFile (file) {
  var extname = path.extname(file.name).toLowerCase()
  return extname === '.torrent'
}

function isNotTorrentFile (file) {
  return !isTorrentFile(file)
}

function addTorrent (torrentId) {
  getClient(function (err, client) {
    if (err) return onError(err)
    var torrent = client.add(torrentId)
    addTorrentEvents(torrent)
  })
}

function seed (files) {
  if (files.length === 0) return
  getClient(function (err, client) {
    if (err) return onError(err)
    var torrent = client.seed(files)
    addTorrentEvents(torrent)
  })
}

function addTorrentEvents (torrent) {
  torrent.on('infoHash', update)
  torrent.on('done', update)
  torrent.on('download', updateThrottled)
  torrent.on('upload', updateThrottled)
  torrent.on('ready', function () {
    torrentReady(torrent)
  })
  update()
}

function torrentReady (torrent) {
  torrentPoster(torrent, function (err, buf) {
    if (err) return onError(err)
    torrent.posterURL = URL.createObjectURL(new Blob([ buf ], { type: 'image/png' }))
    update()
  })
  update()
}

function startServer (torrent, cb) {
  // use largest file
  var index = torrent.files.indexOf(torrent.files.reduce(function (a, b) {
    return a.length > b.length ? a : b
  }))

  var server = torrent.createServer()
  server.listen(0, function () {
    var port = server.address().port
    var urlSuffix = ':' + port + '/' + index
    state.server = {
      server: server,
      localURL: 'http://localhost' + urlSuffix,
      networkURL: 'http://' + networkAddress() + urlSuffix
    }
    cb()
  })
}

function closeServer () {
  state.server.server.destroy()
  state.server = null
}

function openPlayer (torrent) {
  startServer(torrent, function () {
    state.player = 'local'
    update()
  })
}

function closePlayer () {
  closeServer()
  state.player = null
  update()
}

function openChromecast (torrent) {
  startServer(torrent, function () {
    state.view.chromecast.play(state.server.networkURL, { title: 'WebTorrent — ' + torrent.name })
    state.view.chromecast.on('error', function (err) {
      err.message = 'Chromecast: ' + err.message
      onError(err)
    })
    state.player = 'chromecast'
    update()
  })
}

function openAirplay (torrent) {
  startServer(torrent, function () {
    state.view.airplay.play(state.server.networkURL, 0, function () {})
    // TODO: handle airplay errors
    state.player = 'airplay'
    update()
  })
}

function setDimensions (dimensions) {
  state.view.savedWindowBounds = electron.remote.getCurrentWindow().getBounds()

  // Limit window size to screen size
  var workAreaSize = electron.remote.screen.getPrimaryDisplay().workAreaSize
  var width = Math.min(dimensions.width, workAreaSize.width)
  var height = Math.min(dimensions.height, workAreaSize.height)
  var aspectRatio = width / height

  height += HEADER_HEIGHT

  // Center window on screen
  var x = Math.floor((workAreaSize.width - width) / 2)
  var y = Math.floor((workAreaSize.height - height) / 2)

  electron.ipcRenderer.send('setAspectRatio', aspectRatio, { width: 0, height: HEADER_HEIGHT })
  electron.ipcRenderer.send('setBounds', { x, y, width, height })
}

function restoreBounds () {
  electron.ipcRenderer.send('setAspectRatio', 0)
  electron.ipcRenderer.send('setBounds', state.view.savedWindowBounds, true)
}

function onError (err) {
  console.error(err.stack)
  window.alert(err.message || err)
  update()
}

function onWarning (err) {
  console.log('warning: %s', err.message)
}
<|endoftext|>


<commit_before>var Mosto   = require('../models/Mosto')
,   should  = require('should')
,   mvcp    = require('../drivers/mvcp/mvcp-driver')('melted')
,   melted  = require('../api/Melted')
,   helpers = require('./media_helpers')
,   _       = require('underscore')
,   moment  = require('moment')
;

describe.only('models.Mosto', function() {
    var self = this;
    self.playlists = Mosto.Playlists;
    self.medias = helpers.getMedia();
    this.timeout(300000);

    self.createPlaylist = function(medias, start) {
        var duration = _.reduce(medias, function(acc, m) { return acc + m.get('length') * m.get('fps') }, 0);
        start = start || moment();
        var pl = new Mosto.Playlist({
            id: now.valueOf(),
            name: 'test',
            start: moment(now),
            end: now.add(duration),
        });
        pl.get('medias').add(medias);
        return pl;
    };

    describe('MeltedCollection', function(){
        before(function(done) {
            // restart melted
            melted.take(function() {
                melted.stop(function() {
                    melted.start(function() {
                        melted.setup(undefined, undefined, function() {
                            done()
                        });
                    });
                });
            });
        });

        after(function(done) {
            melted.stop(function() {
                melted.leave();
                done();
            });
        });

        describe("Media juggling", function() {
            before(function() {
                self.mlt_media = self.playlists.get('melted_medias');
                self.pls = self.playlists.get('playlists');
                self.mediamodels = _.map(self.medias, function(media, ix) { return new Mosto.Media(_.extend(media, { playlist_order: ix })) });
            });
            describe("starting without medias in melted", function(){
                beforeEach(function(done) {
                    self.mlt_media.take(function() {
                        mvcp.cleanPlaylist().then(function(){ done() }, done).fin(self.mlt_media.leave);
                    });
                });
                afterEach(function(done) {
                    self.pls.set([]);
                    self.playlists.save();
                    self.mlt_media.take(function() {
                        done();
                        self.mlt_media.leave()
                    });
                });
                it("should add it's media to melted", function(done) {
                    var mlt_media = self.mlt_media;
                    var playlists = self.pls;
                    var pl = self.createPlaylist(self.mediamodels);

                    self.playlists.addPlaylist(pl);
                    self.playlists.save();
                    mlt_media.take(function() {
                        mvcp.getServerPlaylist().then(function(clips) {
                            clips.length.should.eql(self.medias.length);
                            clips.forEach(function(clip, ix) {
                                clip.id.should.eql(self.medias[ix].id);
                            });
                        }).then(done, done).fin(mlt_media.leave);
                    });
                });
            });
            describe("starting with media in melted", function() {
                beforeEach(function(done) {
                    var pl = self.createPlaylist(self.mediamodels);
                    self.pls.set(pl);
                    self.playlists.save();
                    self.mlt_media.take(function() {
                        done();
                        self.mlt_media.leave()
                    });
                });
                afterEach(function(done) {
                    self.pls.set([]);
                    self.playlists.save();
                    self.mlt_media.take(function() {
                        done();
                        self.mlt_media.leave()
                    });
                });
                it('A new instance should fetch the playlist from the server', function(done){
                    var mm = new Mosto.MeltedCollection();
                    mm.fetch();
                    mm.take(function() {
                        mm.length.should.eql(self.medias.length);
                        done();
                    });
                });

                describe('remove medias', function() {
                    it('medias removed directly from MeltedCollection should be removed from melted', function(done) {
                        var collection = self.mlt_media;
                        collection.remove(self.mediamodels);
                        collection.take(function() {
                            mvcp.getServerPlaylist().then(function(clips) {
                                clips.length.should.eql(0);
                            }).then(done, done).fin(collection.leave);
                        });
                    });
                    it('but when Playlists.save(), they should be restored', function(done){
                        self.playlists.save();
                        self.mlt_media.take(function(){
                            mvcp.getServerPlaylist().then(function(clips) {
                                clips.length.should.eql(self.medias.length);
                                clips.forEach(function(clip, ix) {
                                    clip.id.should.eql(self.medias[ix].id);
                                });
                            }).then(done, done).fin(self.mlt_media.leave);
                        });
                    });
                    });
                });
            });
        });
    });
});
<commit_msg>test removing whole playlists<commit_after>var Mosto   = require('../models/Mosto')
,   should  = require('should')
,   mvcp    = require('../drivers/mvcp/mvcp-driver')('melted')
,   melted  = require('../api/Melted')
,   helpers = require('./media_helpers')
,   _       = require('underscore')
,   moment  = require('moment')
;

describe.only('models.Mosto', function() {
    var self = this;
    self.playlists = Mosto.Playlists;
    self.medias = helpers.getMedia();
    this.timeout(300000);

    self.createPlaylist = function(medias, start) {
        var duration = _.reduce(medias, function(acc, m) { return acc + m.get('length') * m.get('fps') }, 0);
        start = start || moment();
        var pl = new Mosto.Playlist({
            id: now.valueOf(),
            name: 'test',
            start: moment(now),
            end: now.add(duration),
        });
        pl.get('medias').add(medias);
        return pl;
    };

    describe('MeltedCollection', function(){
        before(function(done) {
            // restart melted
            melted.take(function() {
                melted.stop(function() {
                    melted.start(function() {
                        melted.setup(undefined, undefined, function() {
                            done()
                        });
                    });
                });
            });
        });

        after(function(done) {
            melted.stop(function() {
                melted.leave();
                done();
            });
        });

        describe("Media juggling", function() {
            before(function() {
                self.mlt_media = self.playlists.get('melted_medias');
                self.pls = self.playlists.get('playlists');
                self.mediamodels = _.map(self.medias, function(media, ix) { return new Mosto.Media(_.extend(media, { playlist_order: ix })) });
            });
            describe("starting without medias in melted", function(){
                beforeEach(function(done) {
                    self.mlt_media.take(function() {
                        mvcp.cleanPlaylist().then(function(){ done() }, done).fin(self.mlt_media.leave);
                    });
                });
                afterEach(function(done) {
                    self.pls.set([]);
                    self.playlists.save();
                    self.mlt_media.take(function() {
                        done();
                        self.mlt_media.leave()
                    });
                });
                it("should add it's media to melted", function(done) {
                    var mlt_media = self.mlt_media;
                    var playlists = self.pls;
                    var pl = self.createPlaylist(self.mediamodels);

                    self.playlists.addPlaylist(pl);
                    self.playlists.save();
                    mlt_media.take(function() {
                        mvcp.getServerPlaylist().then(function(clips) {
                            clips.length.should.eql(self.medias.length);
                            clips.forEach(function(clip, ix) {
                                clip.id.should.eql(self.medias[ix].id);
                            });
                        }).then(done, done).fin(mlt_media.leave);
                    });
                });
            });
            describe("starting with media in melted", function() {
                beforeEach(function(done) {
                    var pl = self.createPlaylist(self.mediamodels);
                    self.pls.set(pl);
                    self.playlists.save();
                    self.mlt_media.take(function() {
                        done();
                        self.mlt_media.leave()
                    });
                });
                afterEach(function(done) {
                    self.pls.set([]);
                    self.playlists.save();
                    self.mlt_media.take(function() {
                        done();
                        self.mlt_media.leave()
                    });
                });
                it('A new instance should fetch the playlist from the server', function(done){
                    var mm = new Mosto.MeltedCollection();
                    mm.fetch();
                    mm.take(function() {
                        mm.length.should.eql(self.medias.length);
                        done();
                    });
                });

                describe('remove medias', function() {
                    it('medias removed directly from MeltedCollection should be removed from melted', function(done) {
                        var collection = self.mlt_media;
                        collection.remove(self.mediamodels);
                        collection.take(function() {
                            mvcp.getServerPlaylist().then(function(clips) {
                                clips.length.should.eql(0);
                            }).then(done, done).fin(collection.leave);
                        });
                    });
                    it('but when Playlists.save(), they should be restored', function(done){
                        self.playlists.save();
                        self.mlt_media.take(function(){
                            mvcp.getServerPlaylist().then(function(clips) {
                                clips.length.should.eql(self.medias.length);
                                clips.forEach(function(clip, ix) {
                                    clip.id.should.eql(self.medias[ix].id);
                                });
                            }).then(done, done).fin(self.mlt_media.leave);
                        });
                    });
                    it('removing the Playlist and saving should remove them from melted as well', function(done){
                        var pl = self.pls.at(0);
                        self.playlists.removePlaylist(pl);
                        self.playlists.save();
                        self.mlt_media.take(function() {
                            mvcp.getServerPlaylist().then(function(clips) {
                                clips.length.should.eql(0);
                            }).then(done, done).fin(self.mlt_media.leave);
                        });
                    });
                });
            });
        });
    });
});
<|endoftext|>


<commit_before>/*! Responsive Equalized Heights v1.0.0
 *  https://github.com/jsmreese/responsive-equalized-heights
 *  Date: 2014-12-03
 *
 *  Responsive equalized element heights for ZURB Foundation
 *  http://foundation.zurb.com/
 *
 *  Copyright 2014 John Madhavan-Reese
 *  Released under the MIT license
 */

 (function (window, undefined) {
	"use strict";

	var sizes, sheets, matchers, $, F;

	$ = window.jQuery;
	F = window.Foundation;

	// find
	function find(array, callback) {
		var index, max, match;

		index = 0;
		max = array.length;

		if (typeof callback !== "function") {
			match = callback;
			callback = function (item) {
				return item === match;
			};
		}

		while (index < max) {
			if (callback(array[index])) { return array[index]; }
			index += 1;
		}
	}

	// each
	function each(array, callback) {
		var index, max;

		index = 0;
		max = array.length;

		if (!array || !max) { return; }

		while (index < max) {
			if (callback(array[index], index) === false) { return; }
			index += 1;
		}
	}

	// map
	function map(array, callback) {
		var index = 0,
			max = array.length,
			ret = [];

		if (!array || !max) { return ret; }

		while (index < max) {
			ret[index] = callback(array[index], index);
			index += 1;
		}

		return ret;
	}

	// compact
	function compact(array) {
		var ret = [];

		each(array, function (item) {
			if (item) { ret.push(item); }
		});

		return ret;
	}

	// unique
	function unique(array) {
		var ret = [];

		each(array, function (_a) {
			if (!find(ret, _a)) { ret.push(_a); }
		});

		return ret;
	}

	// create matcher
	function createMatcher(size) {
		matchers[size] = new RegExp(" " + size + "\\-height\\-(\\S+)");
	}

	// create sheet
	function createSheet(size) {
		sheets[size] = createStylesheet(F.media_queries[size]);
	}

	// create a style element
	// returns a reference to the created style element's sheet property.
	// accepts a media query applied to the created stylesheet.
	// inspired by http://davidwalsh.name/add-rules-stylesheets
	function createStylesheet(media) {
		var style;

		// create a style element
		style = document.createElement("style");

		// webkit hack
		style.appendChild(document.createTextNode(""));

		if (media) {
			style.setAttribute("media", media);
		}

		// add the style element to the page
		document.head.appendChild(style);

		return style.sheet;
	}

	// delete rules for all responsive-equalized-heights stylesheets
	function deleteRules() {
		each(sizes, function (size) {
			var sheet = sheets[size];

			while (sheet.cssRules.length) {
				sheet.deleteRule(0);
			}
		});
	}

	// insert a rule into a stylesheet
	function insertRule(sheet, rule) {
		sheet.insertRule(rule, sheet.cssRules.length);
	}

	// get array of active screen sizes
	// the current screen size is the last active size in the array
	function getActiveSizes() {
		return compact(map(sizes, function (size) {
			if (matchMedia(F.media_queries[size]).matches) {
				return size;
			}
		}));
	}

	// update stylesheet rules
	function updateRules() {
		deleteRules();
		addRules();
	}

	// create responsive height rules
	function addRules() {
		var cache, activeSizes, $elems, groups;

		// setup groups and element cache
		groups = [];
		cache = {};
		activeSizes = getActiveSizes();

		each(activeSizes, function (size) {
			cache[size] = {};
		});

		// general selector will find all possible matches
		$elems = $('[class*="-height-"]');

		// filter possible matches to find real size groups
		$elems = $elems.filter(function (index, elem) {
			var match;

			each(activeSizes, function (size) {
				var sizeMatch, group;

				sizeMatch = matchers[size].exec(" " + elem.className);

				if (sizeMatch) {
					group = sizeMatch[1];

					if (group !== "auto") {
						match = true;

						// save group name
						groups.push(group);

						// cache element under size group
						if (cache[size][group]) {
							cache[size][group] = $(cache[size][group]).add(elem);
						} else {
							cache[size][group] = $(elem);
						}
					}
				}
			});

			return match;
		});

		// create unique list of groups
		groups = unique(groups);

		// process each group
		each(groups, function (group) {
			var $group, groupHeight;

			$group = $();

			// add each cached size group, filtering out those elements that have a size override in any larger active size
			each(activeSizes, function (size, sizeIndex) {
				var largerSizes, $sizeGroup;

				if (cache[size][group]) {
					largerSizes = activeSizes.slice(sizeIndex + 1);
					$sizeGroup = cache[size][group];

					if (largerSizes.length) {
						$sizeGroup = $sizeGroup.filter(function (index, elem) {
							var override;

							each(largerSizes, function (largerSize) {
								override = matchers[largerSize].exec(" " + elem.className);

								if (override) { return false; }
							});

							return !override;
						});
					}

					$group = $group.add($sizeGroup);
				}
			});

			// if there are active elements for this group
			// create rules
			if ($group.length) {
				// find max element height in group
				// use outerHeight to include padding and border because of box-sizing: border-box;
				// add one px to account for zoomed factional pixels
				groupHeight = 1 + Math.max.apply(null, $group.map(function (index, elem) { return $(elem).outerHeight(); }));

				// write CSS rules for active sizes and groups
				each(activeSizes, function (size) {
					insertRule(sheets[size], "." + size + "-height-" + group + " { height: " + groupHeight + "px; }");
				});
			}
		});
	}

	// setup sizes
	sizes = "small medium large xlarge xxlarge".split(" ");

	// setup matcher regexps
	matchers = {};
	each(sizes, createMatcher);

	// setup responsive height stylesheets
	sheets = {};
	each(sizes, createSheet);

	// initialize rules
	addRules();

	// window resize handler
	$(window).on("resize", F.utils.throttle(updateRules, 250));

	// expose to the outside world
	F.responsive_heights = {
		stylesheets: sheets,
		update: updateRules,
		remove: deleteRules
	};
})(this);
<commit_msg>Editing comments.<commit_after>/*! Responsive Equalized Heights v1.0.0
 *  https://github.com/jsmreese/responsive-equalized-heights
 *  Date: 2014-12-03
 *
 *  Responsive equalized element heights for ZURB Foundation
 *  http://foundation.zurb.com/
 *
 *  Copyright 2014 John Madhavan-Reese
 *  Released under the MIT license
 */

 (function (window, undefined) {
	"use strict";

	var sizes, sheets, matchers, $, F;

	$ = window.jQuery;
	F = window.Foundation;

	// find
	function find(array, callback) {
		var index, max, match;

		index = 0;
		max = array.length;

		if (typeof callback !== "function") {
			match = callback;
			callback = function (item) {
				return item === match;
			};
		}

		while (index < max) {
			if (callback(array[index])) { return array[index]; }
			index += 1;
		}
	}

	// each
	function each(array, callback) {
		var index, max;

		index = 0;
		max = array.length;

		if (!array || !max) { return; }

		while (index < max) {
			if (callback(array[index], index) === false) { return; }
			index += 1;
		}
	}

	// map
	function map(array, callback) {
		var index = 0,
			max = array.length,
			ret = [];

		if (!array || !max) { return ret; }

		while (index < max) {
			ret[index] = callback(array[index], index);
			index += 1;
		}

		return ret;
	}

	// compact
	function compact(array) {
		var ret = [];

		each(array, function (item) {
			if (item) { ret.push(item); }
		});

		return ret;
	}

	// unique
	function unique(array) {
		var ret = [];

		each(array, function (_a) {
			if (!find(ret, _a)) { ret.push(_a); }
		});

		return ret;
	}

	// create matcher
	function createMatcher(size) {
		matchers[size] = new RegExp(" " + size + "\\-height\\-(\\S+)");
	}

	// create sheet
	function createSheet(size) {
		sheets[size] = createStylesheet(F.media_queries[size]);
	}

	// create a style element
	// returns a reference to the created style element's sheet property.
	// accepts a media query applied to the created stylesheet.
	// inspired by http://davidwalsh.name/add-rules-stylesheets
	function createStylesheet(media) {
		var style;

		// create a style element
		style = document.createElement("style");

		// webkit hack
		style.appendChild(document.createTextNode(""));

		if (media) {
			style.setAttribute("media", media);
		}

		// add the style element to the page
		document.head.appendChild(style);

		return style.sheet;
	}

	// delete rules for all responsive-equalized-heights stylesheets
	function deleteRules() {
		each(sizes, function (size) {
			var sheet = sheets[size];

			while (sheet.cssRules.length) {
				sheet.deleteRule(0);
			}
		});
	}

	// insert a rule into a stylesheet
	function insertRule(sheet, rule) {
		sheet.insertRule(rule, sheet.cssRules.length);
	}

	// get array of active screen sizes
	// the current screen size is the last size in the array
	function getActiveSizes() {
		return compact(map(sizes, function (size) {
			if (matchMedia(F.media_queries[size]).matches) {
				return size;
			}
		}));
	}

	// update stylesheet rules
	function updateRules() {
		deleteRules();
		addRules();
	}

	// create responsive height rules
	function addRules() {
		var cache, activeSizes, $elems, groups;

		// setup groups and element cache
		groups = [];
		cache = {};
		activeSizes = getActiveSizes();

		each(activeSizes, function (size) {
			cache[size] = {};
		});

		// general selector will find all possible matches
		$elems = $('[class*="-height-"]');

		// filter possible matches to find real size groups
		$elems = $elems.filter(function (index, elem) {
			var match;

			each(activeSizes, function (size) {
				var sizeMatch, group;

				sizeMatch = matchers[size].exec(" " + elem.className);

				if (sizeMatch) {
					group = sizeMatch[1];

					if (group !== "auto") {
						match = true;

						// save group name
						groups.push(group);

						// cache element under size group
						if (cache[size][group]) {
							cache[size][group] = $(cache[size][group]).add(elem);
						} else {
							cache[size][group] = $(elem);
						}
					}
				}
			});

			return match;
		});

		// create unique list of groups
		groups = unique(groups);

		// process each group
		each(groups, function (group) {
			var $group, groupHeight;

			$group = $();

			// add each cached size group, filtering out those elements that have a size override in any larger active size
			each(activeSizes, function (size, sizeIndex) {
				var largerSizes, $sizeGroup;

				if (cache[size][group]) {
					largerSizes = activeSizes.slice(sizeIndex + 1);
					$sizeGroup = cache[size][group];

					if (largerSizes.length) {
						$sizeGroup = $sizeGroup.filter(function (index, elem) {
							var override;

							each(largerSizes, function (largerSize) {
								override = matchers[largerSize].exec(" " + elem.className);

								if (override) { return false; }
							});

							return !override;
						});
					}

					$group = $group.add($sizeGroup);
				}
			});

			// if there are active elements for this group
			// create rules
			if ($group.length) {
				// find max element height in group
				// use outerHeight to include padding and border because of box-sizing: border-box;
				// add one px to account for zoomed factional pixels
				groupHeight = 1 + Math.max.apply(null, $group.map(function (index, elem) { return $(elem).outerHeight(); }));

				// write CSS rules for active sizes and groups
				each(activeSizes, function (size) {
					insertRule(sheets[size], "." + size + "-height-" + group + " { height: " + groupHeight + "px; }");
				});
			}
		});
	}

	// setup sizes
	sizes = "small medium large xlarge xxlarge".split(" ");

	// setup matcher regexps
	matchers = {};
	each(sizes, createMatcher);

	// setup responsive height stylesheets
	sheets = {};
	each(sizes, createSheet);

	// initialize rules
	addRules();

	// window resize handler
	$(window).on("resize", F.utils.throttle(updateRules, 250));

	// expose to the outside world
	F.responsive_heights = {
		stylesheets: sheets,
		update: updateRules,
		remove: deleteRules
	};
})(this);
<|endoftext|>


<commit_before>var rpj;

module("test on regexp.js", {
  setup: function () {
    rpj = new Rpj();
  }
});

test("numeric on chkNumeric", function () {
  ok(rpj.chkNumeric("1234567890") === true, "1234567890 is valid");
});

test("numeric on chkAlpha", function () {
  ok(rpj.chkAlpha("1234567890") === false, "1234567890 is invalid");
});

test("numeric on chkAlphaExtra", function () {
  ok(rpj.chkAlphaExtra("1234567890") === false, "1234567890 is invalid");
});

test("numeric on chkUrl", function () {
  ok(rpj.chkUrl("1234567890") === false, "1234567890 is invalid");
});

test("numeric on chkUrl", function () {
  ok(rpj.chkUrl("1234567890") === false, "1234567890 is invalid");
});

test("numeric on chkNumeric with length", function () {
  ok(rpj.chkNumeric("1234567890", 10) === true, "1234567890 is valid");
});

test("numeric on chkNumeric with invalid length", function () {
  ok(rpj.chkNumeric("1234567890", 9) === false, "1234567890 is invalid");
});

test("alpha on chkAlpha", function () {
  ok(rpj.chkAlpha("ABCDE") === true, "ABCDE is invalid");
});

test("alpha on chkNumeric", function () {
  ok(rpj.chkNumeric("ABCDE") === false, "ABCDE is invalid");
});

test("alpha on chkUrl", function () {
  ok(rpj.chkUrl("ABCDE") === false, "ABCDE is invalid");
});

test("alpha on chkAlpha with length", function () {
  ok(rpj.chkAlpha("ABCDE", 5) === true, "ABCDE is invalid");
});

test("alpha on chkAlpha with invalid length", function () {
  ok(rpj.chkAlpha("ABCDE", 4) === false, "ABCDE is invalid");
});

test("alphaextra on chkAlphaExtra", function () {
  ok(rpj.chkAlphaExtra("ABCDE+_-") === true, "ABCDE+_- is invalid");
});

test("alphaextra on chkNumeric", function () {
  ok(rpj.chkNumeric("ABCDE+_-") === false, "ABCDE+_- is invalid");
});

test("alphaextra on chkUrl", function () {
  ok(rpj.chkUrl("ABCDE+_-") === false, "ABCDE+_- is invalid");
});

test("alphaextra on chkAlphaExtra with length", function () {
  ok(rpj.chkAlphaExtra("ABCDE+_-", 8) === true, "ABCDE+_- is valid");
});

test("alphaextra on chkAlphaExtra with invalid length", function () {
  ok(rpj.chkAlphaExtra("ABCDE+_-", 7) === false, "ABCDE+_- is invalid");
});

test("httpurl on chkAlpha", function () {
  ok(rpj.chkAlpha("http://hoge.com") === false, "http://hoge.com is valid");
});

test("httpurl on chkNumeric", function () {
  ok(rpj.chkNumeric("http://hoge.com") === false, "http://hoge.com is invalid");
});

test("httpurl on chkUrl", function () {
  ok(rpj.chkUrl("http://hoge.com") === true, "http://hoge.com is valid");
});

test("httpsurl on chkAlpha", function () {
  ok(rpj.chkAlpha("https://hoge.com") === false, "https://hoge.com is valid");
});

test("httpsurl on chkNumeric", function () {
  ok(rpj.chkNumeric("https://hoge.com") === false, "https://hoge.com is invalid");
});

test("httpsurl on chkUrl", function () {
  ok(rpj.chkUrl("https://hoge.com") === true, "https://hoge.com is valid");
});

test("int on chkNumeric", function () {
  ok(rpj.chkNumeric(12345) === false, "12345 is invalid");
});

test("int on chkAlpha", function () {
  ok(rpj.chkAlpha(12345) === false, "12345 is invalid");
});

test("int on chkAlphaExtra", function () {
  ok(rpj.chkAlphaExtra(12345) === false, "12345 is invalid");
});

test("int on chkUrl", function () {
  ok(rpj.chkUrl(12345) === false, "12345 is invalid");
});

test("array on chkNumeric", function () {
  ok(rpj.chkNumeric([1,2,3,4,5]) === false, "[1,2,3,4,5] is invalid");
});

test("array on chkAlpha", function () {
  ok(rpj.chkAlpha([1,2,3,4,5]) === false, "[1,2,3,4,5] is invalid");
});

test("array on chkAlphaExtra", function () {
  ok(rpj.chkAlphaExtra([1,2,3,4,5]) === false, "[1,2,3,4,5] is invalid");
});

test("array on chkUrl", function () {
  ok(rpj.chkUrl([1,2,3,4,5]) === false, "[1,2,3,4,5] is invalid");
});

test("JSON on chkNumeric", function () {
  ok(rpj.chkNumeric({'hoge':'fuga'}) === false, "{'hoge':'fuga'} is invalid");
});

test("JSON on chkAlpha", function () {
  ok(rpj.chkAlpha({'hoge':'fuga'}) === false, "{'hoge':'fuga'} is invalid");
});

test("JSON on chkAlphaExtra", function () {
  ok(rpj.chkAlphaExtra({'hoge':'fuga'}) === false, "{'hoge':'fuga'} is invalid");
});

test("JSON on chkUrl", function () {
  ok(rpj.chkUrl({'hoge':'fuga'}) === false, "{'hoge':'fuga'} is invalid");
});

test("undefined on chkNumeric", function () {
  ok(rpj.chkNumeric(undefined) === false, "undefined is invalid");
});

test("undefined on chkAlpha", function () {
  ok(rpj.chkAlpha(undefined) === false, "undefined is invalid");
});

test("undefined on chkAlphaExtra", function () {
  ok(rpj.chkAlphaExtra(undefined) === false, "undefined is invalid");
});

test("undefined on chkUrl", function () {
  ok(rpj.chkUrl(undefined) === false, "undefined is invalid");
});

test("null on chkNumeric", function () {
  ok(rpj.chkNumeric(null) === false, "null is invalid");
});

test("null on chkAlpha", function () {
  ok(rpj.chkAlpha(null) === false, "null is invalid");
});

test("null on chkAlphaExtra", function () {
  ok(rpj.chkAlphaExtra(null) === false, "null is invalid");
});

test("null on chkUrl", function () {
  ok(rpj.chkUrl(null) === false, "null is invalid");
});
<commit_msg>Add comment on test code<commit_after>var rpj;

module("test on regexp.js", {
  setup: function () {
    rpj = new Rpj();
  }
});

// numeric test
test("numeric on chkNumeric", function () {
  ok(rpj.chkNumeric("1234567890") === true, "1234567890 is valid");
});

test("numeric on chkAlpha", function () {
  ok(rpj.chkAlpha("1234567890") === false, "1234567890 is invalid");
});

test("numeric on chkAlphaExtra", function () {
  ok(rpj.chkAlphaExtra("1234567890") === false, "1234567890 is invalid");
});

test("numeric on chkUrl", function () {
  ok(rpj.chkUrl("1234567890") === false, "1234567890 is invalid");
});

test("numeric on chkUrl", function () {
  ok(rpj.chkUrl("1234567890") === false, "1234567890 is invalid");
});

test("numeric on chkNumeric with length", function () {
  ok(rpj.chkNumeric("1234567890", 10) === true, "1234567890 is valid");
});

test("numeric on chkNumeric with invalid length", function () {
  ok(rpj.chkNumeric("1234567890", 9) === false, "1234567890 is invalid");
});

// alpha test
test("alpha on chkAlpha", function () {
  ok(rpj.chkAlpha("ABCDE") === true, "ABCDE is invalid");
});

test("alpha on chkNumeric", function () {
  ok(rpj.chkNumeric("ABCDE") === false, "ABCDE is invalid");
});

test("alpha on chkUrl", function () {
  ok(rpj.chkUrl("ABCDE") === false, "ABCDE is invalid");
});

test("alpha on chkAlpha with length", function () {
  ok(rpj.chkAlpha("ABCDE", 5) === true, "ABCDE is invalid");
});

test("alpha on chkAlpha with invalid length", function () {
  ok(rpj.chkAlpha("ABCDE", 4) === false, "ABCDE is invalid");
});

// alphaextra test
test("alphaextra on chkAlphaExtra", function () {
  ok(rpj.chkAlphaExtra("ABCDE+_-") === true, "ABCDE+_- is invalid");
});

test("alphaextra on chkNumeric", function () {
  ok(rpj.chkNumeric("ABCDE+_-") === false, "ABCDE+_- is invalid");
});

test("alphaextra on chkUrl", function () {
  ok(rpj.chkUrl("ABCDE+_-") === false, "ABCDE+_- is invalid");
});

test("alphaextra on chkAlphaExtra with length", function () {
  ok(rpj.chkAlphaExtra("ABCDE+_-", 8) === true, "ABCDE+_- is valid");
});

test("alphaextra on chkAlphaExtra with invalid length", function () {
  ok(rpj.chkAlphaExtra("ABCDE+_-", 7) === false, "ABCDE+_- is invalid");
});

// httpurl test
test("httpurl on chkAlpha", function () {
  ok(rpj.chkAlpha("http://hoge.com") === false, "http://hoge.com is valid");
});

test("httpurl on chkNumeric", function () {
  ok(rpj.chkNumeric("http://hoge.com") === false, "http://hoge.com is invalid");
});

test("httpurl on chkUrl", function () {
  ok(rpj.chkUrl("http://hoge.com") === true, "http://hoge.com is valid");
});

// httpsurl test
test("httpsurl on chkAlpha", function () {
  ok(rpj.chkAlpha("https://hoge.com") === false, "https://hoge.com is valid");
});

test("httpsurl on chkNumeric", function () {
  ok(rpj.chkNumeric("https://hoge.com") === false, "https://hoge.com is invalid");
});

test("httpsurl on chkUrl", function () {
  ok(rpj.chkUrl("https://hoge.com") === true, "https://hoge.com is valid");
});

// int test
test("int on chkNumeric", function () {
  ok(rpj.chkNumeric(12345) === false, "12345 is invalid");
});

test("int on chkAlpha", function () {
  ok(rpj.chkAlpha(12345) === false, "12345 is invalid");
});

test("int on chkAlphaExtra", function () {
  ok(rpj.chkAlphaExtra(12345) === false, "12345 is invalid");
});

test("int on chkUrl", function () {
  ok(rpj.chkUrl(12345) === false, "12345 is invalid");
});

// array test
test("array on chkNumeric", function () {
  ok(rpj.chkNumeric([1,2,3,4,5]) === false, "[1,2,3,4,5] is invalid");
});

test("array on chkAlpha", function () {
  ok(rpj.chkAlpha([1,2,3,4,5]) === false, "[1,2,3,4,5] is invalid");
});

test("array on chkAlphaExtra", function () {
  ok(rpj.chkAlphaExtra([1,2,3,4,5]) === false, "[1,2,3,4,5] is invalid");
});

test("array on chkUrl", function () {
  ok(rpj.chkUrl([1,2,3,4,5]) === false, "[1,2,3,4,5] is invalid");
});

// JSON test
test("JSON on chkNumeric", function () {
  ok(rpj.chkNumeric({'hoge':'fuga'}) === false, "{'hoge':'fuga'} is invalid");
});

test("JSON on chkAlpha", function () {
  ok(rpj.chkAlpha({'hoge':'fuga'}) === false, "{'hoge':'fuga'} is invalid");
});

test("JSON on chkAlphaExtra", function () {
  ok(rpj.chkAlphaExtra({'hoge':'fuga'}) === false, "{'hoge':'fuga'} is invalid");
});

test("JSON on chkUrl", function () {
  ok(rpj.chkUrl({'hoge':'fuga'}) === false, "{'hoge':'fuga'} is invalid");
});

// undefined test
test("undefined on chkNumeric", function () {
  ok(rpj.chkNumeric(undefined) === false, "undefined is invalid");
});

test("undefined on chkAlpha", function () {
  ok(rpj.chkAlpha(undefined) === false, "undefined is invalid");
});

test("undefined on chkAlphaExtra", function () {
  ok(rpj.chkAlphaExtra(undefined) === false, "undefined is invalid");
});

test("undefined on chkUrl", function () {
  ok(rpj.chkUrl(undefined) === false, "undefined is invalid");
});

// null test
test("null on chkNumeric", function () {
  ok(rpj.chkNumeric(null) === false, "null is invalid");
});

test("null on chkAlpha", function () {
  ok(rpj.chkAlpha(null) === false, "null is invalid");
});

test("null on chkAlphaExtra", function () {
  ok(rpj.chkAlphaExtra(null) === false, "null is invalid");
});

test("null on chkUrl", function () {
  ok(rpj.chkUrl(null) === false, "null is invalid");
});
<|endoftext|>


<commit_before>var http = require('http');

var req = require('../src/request.js');
var uri = req.uri;
var request = req.request;

describe("Request", function () {

  it("fails to match a uri", function () {
    var testRequest = {
        url:  "/charmander/5"
    };

    expect(request(uri("/pikachu/[0-9]+"))
           .matches(testRequest))
      .toBe(false);
  });

  it("matches a uri", function () {
    var testRequest = {
        url:  "/kittens/3"
    };

    expect(request(uri("/kittens/[0-9]+"))
           .matches(testRequest))
      .toBe(true);
  });

  it("matches from criteria", function () {
    var testRequest = {
      url : "/pikachu/50"
    };

    expect(request(uri("/pikachu/.*"))
           .matches(testRequest))
      .toBe(true);
  });

  it("matches two criteria", function () {
    var testRequest = {
      url : "/bulbasaur/4"
    };

    expect(request(uri("/bulbasaur/4"),
                   uri("/bulbasaur/[0-9]+"))
           .matches(testRequest))
      .toBe(true);
  });

  it("fails on the second criteria", function () {
    var testRequest = {
      url : "/squirtle/50"
    };

    expect(request(uri("/bulbasaur/[0-9]+"),
                   uri("/bulbasaur/40"))
           .matches(testRequest))
      .toBe(false);
  });
});<commit_msg>Remove unused import.<commit_after>var req = require('../src/request.js');
var uri = req.uri;
var request = req.request;

describe("Request", function () {

  it("fails to match a uri", function () {
    var testRequest = {
        url:  "/charmander/5"
    };

    expect(request(uri("/pikachu/[0-9]+"))
           .matches(testRequest))
      .toBe(false);
  });

  it("matches a uri", function () {
    var testRequest = {
        url:  "/kittens/3"
    };

    expect(request(uri("/kittens/[0-9]+"))
           .matches(testRequest))
      .toBe(true);
  });

  it("matches from criteria", function () {
    var testRequest = {
      url : "/pikachu/50"
    };

    expect(request(uri("/pikachu/.*"))
           .matches(testRequest))
      .toBe(true);
  });

  it("matches two criteria", function () {
    var testRequest = {
      url : "/bulbasaur/4"
    };

    expect(request(uri("/bulbasaur/4"),
                   uri("/bulbasaur/[0-9]+"))
           .matches(testRequest))
      .toBe(true);
  });

  it("fails on the second criteria", function () {
    var testRequest = {
      url : "/squirtle/50"
    };

    expect(request(uri("/bulbasaur/[0-9]+"),
                   uri("/bulbasaur/40"))
           .matches(testRequest))
      .toBe(false);
  });
});<|endoftext|>