<commit_before>(function () {
  'use strict';

  // Store a local reference to jQuery and Underscorea.
  var $ = window.jQuery;
  var _ = window._;

  var Hangover = window.Hangover = function (el, anchor, options) {
    _.extend(this, options);
    _.bindAll(this,
      'onMouseover', 'onMouseout', 'onFocus', 'onBlur', 'onClick'
    );
    _.each(['hover', 'focus', 'click'], function (type) {
      this[type] = !!~this.action.indexOf(type);
    }, this);
    this.hovered = this.focused = this.clicked = false;
    this.buildContainer().setElement(el).setAnchor(anchor);
  };

  _.extend(Hangover.prototype, {

    // The position of $el relative to the $anchor.
    position: 'top',

    // Display $el the following actions occur (hover, focus, and/or click).
    action: 'hover focus',

    // Preserve $el's listeners and data by using detach instead of remove.
    preserve: false,

    // Set the $el property.
    setElement: function (el) {
      this.$container.empty().append(this.$el = el instanceof $ ? el : $(el));
      return this;
    },

    // Set up the $el container.
    buildContainer: function () {
      this.$container = $('<div>')
        .addClass('js-hangover-container ' +
          _.map(this.position.split(' '), function (dir) {
            return 'js-hangover-' + dir;
          }).join(' ')
        )
        .on('click', 'js-hover-hide', this._hide);
      return this;
    },

    // Set the $anchor property.
    setAnchor: function (anchor) {
      if (this.$anchor) this.$anchor.css('position', null);
      (this.$anchor = anchor instanceof $ ? anchor : $(anchor)).on({
        mouseover: this.onMouseover,
        mouseout: this.onMouseout,
        focus: this.onFocus,
        blur: this.onBlur
      }).css('position', 'relative');
      $(document).click(this.onClick);
      return this;
    },

    // Show the $container.
    show: function () {
      this.$anchor.parent().append(this.$container);
      this.move();
      return this;
    },

    // Hide the $container.
    hide: function () {
      this.$container[this.preserve ? 'detach' : 'remove']();
      this.hovered = this.focused = this.clicked = false;
      return this;
    },

    move: function () {
      var $container = this.$container;
      var $anchor = this.$anchor;
      var divWidth = $container.outerWidth();
      var divHeight = $container.outerHeight();
      var tPosition = $anchor.position();
      var tLeft = tPosition.left + parseInt($anchor.css('marginLeft'), 10);
      var tTop = tPosition.top + parseInt($anchor.css('marginTop'), 10);
      var tWidth = $anchor.outerWidth();
      var tHeight = $anchor.outerHeight();
      var position = {
        left: tLeft,
        top: tTop
      };
      switch (this.position) {
      case 'top':
        position.left += (tWidth - divWidth) / 2;
        position.top -= divHeight;
        break;
      case 'right':
        position.left += tWidth;
        position.top += (tHeight - divHeight) / 2;
        break;
      case 'bottom':
        position.left += (tWidth - divWidth) / 2;
        position.top += tHeight;
        break;
      case 'left':
        position.left -= divWidth;
        position.top += (tHeight - divHeight) / 2;
        break;
      }
      this.$container.css(position);
      return this;
    },

    destroy: function () {
      this.hide();
      this.$anchor.off({
        mouseover: this.onMouseover,
        mouseout: this.onMouseout,
        focus: this.onFocus,
        blur: this.onBlur
      });
      $(document).off(this.onClick);
      return this;
    },

    onMouseover: function () {
      if (!this.hover) return;
      this.hovered = true;
      this.show();
    },

    onMouseout: function () {
      if (!this.hover) return;
      this.hovered = false;
      if ((!this.click || !this.clicked) &&
          (!this.focus || !this.focused)) {
        this.hide();
      }
    },

    onFocus: function () {
      if (!this.focus) return;
      this.focused = true;
      this.show();
    },

    onBlur: function () {
      if (!this.focus) return;
      this.focused = false;
      if ((!this.click || !this.clicked) &&
          (!this.hover || !this.hovered)) {
        this.hide();
      }
    },

    onClick: function (ev) {
      if (!this.click) return;
      if (!this.clicked) {
        var anchorClicked =
          ev.target === this.$anchor[0] ||
          $.contains(this.$anchor[0], ev.target);
        if (!anchorClicked) return;
        this.clicked = true;
        return this.show();
      }
      if ($.contains(this.$container[0], ev.target)) return;
      this.clicked = false;
      return this.hide();
    }
  });
})();
<commit_msg>Clean up move method<commit_after>(function () {
  'use strict';

  // Store a local reference to jQuery and Underscorea.
  var $ = window.jQuery;
  var _ = window._;

  var Hangover = window.Hangover = function (el, anchor, options) {
    _.extend(this, options);
    _.bindAll(this,
      'onMouseover', 'onMouseout', 'onFocus', 'onBlur', 'onClick'
    );
    _.each(['hover', 'focus', 'click'], function (type) {
      this[type] = !!~this.action.indexOf(type);
    }, this);
    this.hovered = this.focused = this.clicked = false;
    this.buildContainer().setElement(el).setAnchor(anchor);
  };

  _.extend(Hangover.prototype, {

    // The position of $el relative to the $anchor.
    position: 'top',

    // Display $el the following actions occur (hover, focus, and/or click).
    action: 'hover focus',

    // Preserve $el's listeners and data by using detach instead of remove.
    preserve: false,

    // Set the $el property.
    setElement: function (el) {
      this.$container.empty().append(this.$el = el instanceof $ ? el : $(el));
      return this;
    },

    // Set up the $el container.
    buildContainer: function () {
      this.$container = $('<div>')
        .addClass('js-hangover-container ' +
          _.map(this.position.split(' '), function (dir) {
            return 'js-hangover-' + dir;
          }).join(' ')
        )
        .on('click', 'js-hover-hide', this._hide);
      return this;
    },

    // Set the $anchor property.
    setAnchor: function (anchor) {
      if (this.$anchor) this.$anchor.css('position', null);
      (this.$anchor = anchor instanceof $ ? anchor : $(anchor)).on({
        mouseover: this.onMouseover,
        mouseout: this.onMouseout,
        focus: this.onFocus,
        blur: this.onBlur
      }).css('position', 'relative');
      $(document).click(this.onClick);
      return this;
    },

    // Show the $container.
    show: function () {
      this.$anchor.parent().append(this.$container);
      this.move();
      return this;
    },

    // Hide the $container.
    hide: function () {
      this.$container[this.preserve ? 'detach' : 'remove']();
      this.hovered = this.focused = this.clicked = false;
      return this;
    },

    move: function () {
      var $container = this.$container;
      var $anchor = this.$anchor;
      var cWidth = $container.outerWidth();
      var cHeight = $container.outerHeight();
      var aWidth = $anchor.outerWidth();
      var aHeight = $anchor.outerHeight();
      var aPosition = $anchor.position();
      var position = {
        left: aPosition.left + parseInt($anchor.css('marginLeft'), 10),
        top: aPosition.top + parseInt($anchor.css('marginTop'), 10)
      };
      switch (this.position) {
      case 'top':
        position.left += (aWidth - cWidth) / 2;
        position.top -= cHeight;
        break;
      case 'right':
        position.left += aWidth;
        position.top += (aHeight - cHeight) / 2;
        break;
      case 'bottom':
        position.left += (aWidth - cWidth) / 2;
        position.top += aHeight;
        break;
      case 'left':
        position.left -= cWidth;
        position.top += (aHeight - cHeight) / 2;
        break;
      }
      this.$container.css(position);
      return this;
    },

    destroy: function () {
      this.hide();
      this.$anchor.off({
        mouseover: this.onMouseover,
        mouseout: this.onMouseout,
        focus: this.onFocus,
        blur: this.onBlur
      });
      $(document).off(this.onClick);
      return this;
    },

    onMouseover: function () {
      if (!this.hover) return;
      this.hovered = true;
      this.show();
    },

    onMouseout: function () {
      if (!this.hover) return;
      this.hovered = false;
      if ((!this.click || !this.clicked) &&
          (!this.focus || !this.focused)) {
        this.hide();
      }
    },

    onFocus: function () {
      if (!this.focus) return;
      this.focused = true;
      this.show();
    },

    onBlur: function () {
      if (!this.focus) return;
      this.focused = false;
      if ((!this.click || !this.clicked) &&
          (!this.hover || !this.hovered)) {
        this.hide();
      }
    },

    onClick: function (ev) {
      if (!this.click) return;
      if (!this.clicked) {
        var anchorClicked =
          ev.target === this.$anchor[0] ||
          $.contains(this.$anchor[0], ev.target);
        if (!anchorClicked) return;
        this.clicked = true;
        return this.show();
      }
      if ($.contains(this.$container[0], ev.target)) return;
      this.clicked = false;
      return this.hide();
    }
  });
})();
<|endoftext|>


<commit_before>

var async = require("./../node_modules/async");

function theQ (options, Node) {

  var self = this;
  var idType;

  self.output = {};
  self.input = {};

  // building options
  if (options.useOriginalID) {
    idType = "_id";
  } else {
    idType = "osm_id";
  }

  if (!!options.upsert) {
    self.save = upsert;
  } else {
    self.save = save;
  }

  var wayFunction
  if (!!options.way.populateGeometry) {
    wayFunction = populateWayGeo;
  } else {
    wayFunction = standardWay;
  }

  // private functions
  function saveCB (err, doc) {
    if (!!err) return console.log(err);
    var type = doc.constructor.modelName;
    self.input[type] = self.input[type]+1 || 1;
  }

  function upsert () {
    var Model = this.model(this.constructor.modelName),
        value = this.toObject(),
        query = {};
    query[idType] = value.osm_id;
    delete value._id;
    Model.findOneAndUpdate(query, value, {upsert: true}, saveCB);
  }

  function save() {
    this.save(saveCB);
  }

  function populateWayGeo (way, cb) {
    var Node = way.constructor.base.models.node;
    var query = {};
    query[idType] = {$in: way.loc.nodes};
    var select = {"loc.coordinates": true};
    select[idType] = true;

    Node.find( query, select, populateWay);

    function populateWay (err, doc) {
      if (err) return console.log(err, way);

      var i = way.loc.nodes.length;
      var coords = [];

      for (i;i--;) {// array to match to
        var b = doc.length;
        var nodeID = way.loc.nodes[i];
        for (b;b--;) {// array being matched
          if (doc[b] && doc[b][idType] === nodeID) {
            coords.unshift(doc[b].loc.coordinates);
            continue;
          }
        }
      }

      way.set('loc.coordinates', coords);
      var isCircularId = way.loc.nodes[0] === way.loc.nodes[way.loc.nodes.length-1];
      var isCircularLtLng = coords[0] === coords[coords.length-1];

      if (isCircularId || isCircularLtLng ) {
        way.set('loc.type', 'Polygon');
      } else {
        way.set('loc.type', 'LineString');
      }

      self.save.call(way);
      cb();
    }
  }

  function standardWay (way, cb) {
    var isCircularId = way.loc.nodes[0] === way.loc.nodes[way.loc.nodes.length-1];
    if (isCircularId) {
      way.set( 'loc.type', 'Polygon');
    } else {
      way.set( 'loc.type', 'LineString');
    }
    self.save.call(way);
    cb();
  }

  // public queues
  self.processNode = function (node, cb) {
    var type = node.constructor.modelName;
    self.output[type] = self.output[type]+1 || 1;
    node.set("loc.type", "Point");
    self.save.call(node);
    cb();
  };

  self.processWay = function (way, cb) {
    var type = node.constructor.modelName;
    self.output[type] = self.output[type]+1 || 1;
    wayFunction(way,cb);
  };

  self.processRelation = function (relation, cb) {
    var type = node.constructor.modelName;
    self.output[type] = self.output[type]+1 || 1;

    // TODO: Create different geometries depending on the relations tags, e.g. type=multipolygon should be a
    //       MultiPolygon.
    // TODO: The following might also break if a relation includes a relation as a member, but the
    //       included relation has not been processed yet.

    var counter = relation.members.length;
    var features = [];

    for (var index = 0; index < relation.members.length; index++) {
      var member = relation.members[index];
      var query = {};
      query[idType] = member.ref;

      models[member.type].findOne(query, function(err, object) {
        if (!!err) return console.log(err);

        if (object == null) {
          console.log("Warning, generating incomplete geometry for relation " + relation.osm_id + " due to missing member " + member.ref + " (" + member.type + ")");
          object = { loc: undefined }; // Such that the following code will not break
        }

        features[index] = { type: "Feature", geometry: object.loc, role: member.role };
        // TODO: Slightly non standard here as the above feature contains a role?
        counter--;
        if (counter == 0) {
          relation.set("loc", { type: "FeatureCollection", features: features });
          save(Relation, relation);
        }
      });
    }

    /*
function sortDependantRelations() {
  for (var i=0; i<dependantRelationQueue.length; i++) {
    var relation = dependantRelationQueue[i];

    // Create a list of all the members which are relations
    var relationMembers = []
    for (var m=0; m<relation.members.length; m++) {
      var member = relation.members[m];
      if (member.type === "relation")
        relationMembers.push(parseInt(member.ref));
    }

    // For every relation that is scheduled to be processed after this one
    for (var j=i+1; j<dependantRelationQueue.length; j++) {
      var otherRelation = dependantRelationQueue[j];

      // Check if it is depended on by 'relation'
      if (relationMembers.indexOf(otherRelation.osm_id) != -1) {
        // If so, swap them
        dependantRelationQueue[i] = otherRelation;
        dependantRelationQueue[j] = relation;
        // Then process 'otherRelation' (now at position i)
        i--; // Repeat for i
        break;
      }
    }
  }
}
*/

    self.save(relation);
    cb();
  };

  self.node = async.queue(self.processNode, 1);
  self.way  = async.queue(self.processWay, 1);
  self.relation = async.queue(self.processRelation, 1);

  return self;
};

module.exports = theQ;

<commit_msg>Due to the ambiguous size of relations and their massive nature, its best not to pre-populate them in the database.<commit_after>

var async = require("./../node_modules/async");

function theQ (options, Node) {

  var self = this;
  var idType;

  self.output = {};
  self.input = {};

  // building options
  if (options.useOriginalID) {
    idType = "_id";
  } else {
    idType = "osm_id";
  }

  if (!!options.upsert) {
    self.save = upsert;
  } else {
    self.save = save;
  }

  var wayFunction
  if (!!options.way.populateGeometry) {
    wayFunction = populateWayGeo;
  } else {
    wayFunction = standardWay;
  }

  // private functions
  function saveCB (err, doc) {
    if (!!err) return console.log(err);
    var type = doc.constructor.modelName;
    self.input[type] = self.input[type]+1 || 1;
  }

  function upsert () {
    var Model = this.model(this.constructor.modelName),
        value = this.toObject(),
        query = {};
    query[idType] = value.osm_id;
    delete value._id;
    Model.findOneAndUpdate(query, value, {upsert: true}, saveCB);
  }

  function save() {
    this.save(saveCB);
  }

  function populateWayGeo (way, cb) {
    var Node = way.constructor.base.models.node;
    var query = {};
    query[idType] = {$in: way.loc.nodes};
    var select = {"loc.coordinates": true};
    select[idType] = true;

    Node.find( query, select, populateWay);

    function populateWay (err, doc) {
      if (err) return console.log(err, way);

      var i = way.loc.nodes.length;
      var coords = [];

      for (i;i--;) {// array to match to
        var b = doc.length;
        var nodeID = way.loc.nodes[i];
        for (b;b--;) {// array being matched
          if (doc[b] && doc[b][idType] === nodeID) {
            coords.unshift(doc[b].loc.coordinates);
            continue;
          }
        }
      }

      way.set('loc.coordinates', coords);
      var isCircularId = way.loc.nodes[0] === way.loc.nodes[way.loc.nodes.length-1];
      var isCircularLtLng = coords[0] === coords[coords.length-1];

      if (isCircularId || isCircularLtLng ) {
        way.set('loc.type', 'Polygon');
      } else {
        way.set('loc.type', 'LineString');
      }

      self.save.call(way);
      cb();
    }
  }

  function standardWay (way, cb) {
    var isCircularId = way.loc.nodes[0] === way.loc.nodes[way.loc.nodes.length-1];
    if (isCircularId) {
      way.set( 'loc.type', 'Polygon');
    } else {
      way.set( 'loc.type', 'LineString');
    }
    self.save.call(way);
    cb();
  }

  // public queues
  self.processNode = function (node, cb) {
    var type = node.constructor.modelName;
    self.output[type] = self.output[type]+1 || 1;
    node.set("loc.type", "Point");
    self.save.call(node);
    cb();
  };

  self.processWay = function (way, cb) {
    var type = node.constructor.modelName;
    self.output[type] = self.output[type]+1 || 1;
    wayFunction(way,cb);
  };

  self.processRelation = function (relation, cb) {
    var type = node.constructor.modelName;
    self.output[type] = self.output[type]+1 || 1;
    self.save(relation);
    cb();
  };

  self.node = async.queue(self.processNode, 1);
  self.way  = async.queue(self.processWay, 1);
  self.relation = async.queue(self.processRelation, 1);

  return self;
};

module.exports = theQ;

<|endoftext|>


<commit_before>"use strict";

var
  http = require('http'),
  httpProxy = require('http-proxy'),
  validUrl = require('valid-url'),
  parse_url = require('url').parse,
  path = require('path'),
  _ = require('lodash'),
  bunyan = require('bunyan');

function ReverseProxy(opts){
  if(!(this instanceof ReverseProxy)){
    return new ReverseProxy(opts);
  }

  opts = opts || {};
  opts.port = opts.port || 8080;

  var log;
  if(opts.bunyan != false){
    log = this.log = bunyan.createLogger(opts.bunyan || {
      name: 'redbird'
    });
  }

  var _this = this;

  //
  // Routing table.
  //
  var routing = this.routing = {};

  //
  // Create a proxy server with custom application logic
  //
  var proxy = this.proxy = httpProxy.createProxyServer({
    xfwd: true,
    prependPath: false
  });

  proxy.on('proxyReq', function(p, req, res, options) {
    if (req.host != null) {
      p.setHeader('host', req.host);
    }
  });

  //
  // Standard HTTP Proxy Server.
  //
  var server = this.server = require('http').createServer(function(req, res) {
    var src = getSource(req);
    var target = _this._getTarget(src, req);
    if(target){
      //
      // Automatically redirect to the HTTPS proxy if there are
      // certificates for this hostname.
      //
      if(certs && src in certs && target.sslRedirect){
        req.url = req._url || req.url; // Get the original url since we are going to redirect.
        redirectToHttps(req, res, target, opts.ssl, log);
      }else{
        proxy.web(req, res, {target: target});
      }
    }else {
      notFound(res);
    }
  });

  //
  // Listen to the `upgrade` event and proxy the
  // WebSocket requests as well.
  //
  server.on('upgrade', websocketsUpgrade);

  server.on('error', function(err){
    log && log.error(err, "Server Error");
  })

  //
  // Optionally create an https proxy server.
  //
  if(opts.ssl){
    var https = require('https');
    var certs = this.certs = {};

    var ssl = {
      SNICallback: function(hostname){
        return certs[hostname];
      },
      //
      // Default certs for clients that do not support SNI.
      //
      key: getCertData(opts.ssl.key),
      cert: getCertData(opts.ssl.cert)
    }

    if(opts.ssl.ca){
      ssl.ca = getCertData(opts.ssl.ca, true);
    }

    if(opts.ssl.opts){
      ssl = _.defaults(ssl, opts.ssl.opts);
    }

    var httpsServer = this.httpsServer = https.createServer(ssl, function(req, res){

      var src = getSource(req);

      var target = _this._getTarget(src, req);
      if(target){
        proxy.web(req, res, {target: target});
      }else {
        notFound(res);
      }
    });

    httpsServer.on('upgrade', websocketsUpgrade);

    httpsServer.on('error', function(err){
      log && log.error(err, "HTTPS Server Error");
    });

    httpsServer.on('clientError', function(err){
      log && log.error(err, "HTTPS Client  Error");
    });

    log && log.info("Listening to HTTPS requests on port %s", opts.ssl.port);
    httpsServer.listen(opts.ssl.port);
  }

  function websocketsUpgrade(req, socket, head){
    var src = getSource(req);
    var target = _this._getTarget(src, req);
    log && log.info({headers: req.headers, target: target}, "upgrade to websockets");
    if(target){
      proxy.ws(req, socket, head, {target: target});
    }else{
      notFound(socket);
    }
  }

  proxy.on('error', function(err, req, res){
    //
    // Send a 500 http status if headers have been sent
    //
    if (!res.headersSent) {
      res.writeHead(500);
    }

    //
    // Do not log this common error
    //
    if(err.message !== 'socket hang up'){
      log && log.error(err, "Proxy Error");
    }
  })

  server.listen(opts.port);

  log && log.info(opts.port, "Started a Redbird reverse proxy server");
}

/**
  Register a new route.

  @src {String|URL} A string or a url parsed by node url module.
  Note that port is ignored, since the proxy just listens to one port.

  @target {String|URL} A string or a url parsed by node url module.
  @opts {Object} Route options.
*/
ReverseProxy.prototype.register = function(src, target, opts){
  if(!src || !target){
    throw Error("Cannot register a new route with unspecified src or target");
  }

  var routing = this.routing;

  src = prepareUrl(src);
  target = prepareUrl(target);

  target.sslRedirect = true;
  target.useTargetHostHeader = false;

  if(opts){
    if(opts.ssl){
      if(!this.httpsServer){
        throw Error("Cannot register https routes without defining a ssl port");
      }

      target.sslRedirect = opts.ssl.redirect === false ? false : true;

      if(!this.certs[src.hostname]){
        if(opts.ssl.key || opts.ssl.cert || opts.ssl.ca){
          var cert = createCredentialContext(opts.ssl.key, opts.ssl.cert, opts.ssl.ca);
          this.certs[src.hostname] = cert;
        }else{
          // Trigger the use of the default certificates.
          this.certs[src.hostname] = undefined;
        }
      }
    }
    target.useTargetHostHeader = opts.useTargetHostHeader === true ? true : false;
  }

  var host = routing[src.hostname] = routing[src.hostname] || [];
  var pathname = src.pathname || '/';
  var route = _.find(host, {path: pathname});

  if(!route){
    route = {path: pathname, rr: 0, urls: []};
    host.push(route);

    //
    // Sort routes
    //
    routing[src.hostname] = _.sortBy(host, function(route){
      return -route.path.length;
    });
  }

  route.urls.push(target);

  this.log && this.log.info({from: src, to: target}, "Registered a new route");
}

ReverseProxy.prototype.unregister = function(src, target){
  if(!src) return;

  src = prepareUrl(src);
  var routes = this.routing[src.hostname] || [];
  var pathname = src.pathname || '/';
  var i;

  for(i=0; i<routes.length; i++){
    if(routes[i].path == pathname){
      break;
    }
  }

  if(i < routes.length){
    var route = routes[i];

    if(target){
      target = prepareUrl(target);
      _.remove(route.urls, function(url){
        return url.href == target.href;
      });
    }else{
      route.urls = []
    }

    if(route.urls.length == 0){
      routes.splice(i, 1);
    }

    this.log && this.log.info({from: src, to: target}, "Unregistered a route");
  }
}

ReverseProxy.prototype.resolve = function(host, url){
  // Given a src resolve it to a target route if any available.
  if(!host) return;

  url = url || '/';

  var routes = this.routing[host];
  var i = 0, path;

  if(routes){
    var len = routes.length;

    //
    // Find path that matches the start of req.url
    //
    for(i=0; i<len; i++){
      var route = routes[i];
      if(startsWith(url, route.path)){
        return route;
      }
    }
  }
}

ReverseProxy.prototype._getTarget = function(src, req){
  var url = req.url;
  var route = this.resolve(src, url);

  if(!route) {
    this.log && this.log.warn(src, 'no valid route found for given source')
    return;
  }

  var pathname = route.path;
  if(pathname.length > 1){
    //
    // remove prefix from src
    //
    req._url = url; // save original url
    req.url = url.substr(pathname.length) || '/'
  }

  //
  // Perform Round Robin on the available targets
  //
  var urls = route.urls;
  var j = route.rr;
  route.rr = (j + 1) % urls.length; // get and update Round robin index.
  var target = route.urls[j];

  //
  // Fix request url if targetname specified.
  //
  if(target.pathname){
    req.url = path.join(target.pathname, req.url);
  }

  //
  // Host headers are passed through from the source by default
  // Often we want to use the host header of the target instead
  //
  if (target.useTargetHostHeader === true) {
    req.host = target.host;
  }

  this.log && this.log.info("Proxying %s to %s", src + url, path.join(target.host, req.url))

  return target;
}

ReverseProxy.prototype.close = function(){
  try{
    this.server.close();
    this.httpsServer && this.httpsServer.close();
  }catch(err){
    // Ignore for now...
  }
}

//
// Helpers
//
function getSource(req){
  if(req.headers.host){
    return req.headers.host.split(':')[0]
  }
}

/**
  Routing table structure. An object with hostname as key, and an array as value.
  The array has one element per path associated to the given hostname.
  Every path has a RoundRobin value (rr) and urls array, with all the urls available
  for this target route.

  {
    hostA :
      [
        {
          path: '/',
          rr: 3,
          urls: []
        }
      ]
  }
*/

function notFound(res){
  res.write("Not Found");
  res.statusCode = 404;
  res.end();
}

//
// Redirect to the HTTPS proxy
//
function redirectToHttps(req, res, target, ssl, log){
  var hostname = req.headers.host.split(':')[0] + ':' + (ssl.redirectPort || ssl.port);
  var url = 'https://'+path.join(hostname, req.url);
  log && log.info("Redirecting %s to %s", path.join(req.headers.host, req.url), url);
  //
  // We can use 301 for permanent redirect, but its bad for debugging, we may have it as
  // a configurable option.
  //
  res.writeHead(302, {Location: url});
  res.end();
}

function startsWith(input, str){
  return input.slice(0, str.length) == str;
}

function prepareUrl(url){
  if(_.isString(url)){
    url = setHttp(url);

    if(!validUrl.isHttpUri(url)){
      throw Error('uri is not a valid http uri ' + url);
    }

    url = parse_url(url);
  }
  return url;
}

function getCertData(pathname, unbundle){
  var fs = require('fs');

  // TODO: Support input as Buffer, Stream or Pathname.

  if(pathname){
    if(_.isArray(pathname)){
      var pathnames = pathname;
      return _.flatten(_.map(pathnames, function(pathname){
        return getCertData(pathname, unbundle);
      }));
    }else if(fs.existsSync(pathname)){
      if(unbundle){
        return unbundleCert(fs.readFileSync(pathname, 'utf8'));
      }else{
        return fs.readFileSync(pathname, 'utf8');
      }
    }
  }
}

/**
  Unbundles a file composed of several certificates.
  http://www.benjiegillam.com/2012/06/node-dot-js-ssl-certificate-chain/
*/
function unbundleCert(bundle){
  var chain = bundle.trim().split("\n");

  var ca = [];
  var cert = [];

  for (var i = 0, len = chain.length; i < len; i++) {
    var line = chain[i].trim();
    if (!(line.length !== 0)) {
      continue;
    }
    cert.push(line);
    if (line.match(/-END CERTIFICATE-/)) {
      var joined = cert.join("\n");
      ca.push(joined);
      cert = [];
    }
  }
  return ca;
}

function createCredentialContext(key, cert, ca) {
  var crypto = require('crypto');

  var details = {};

  details.key = getCertData(key);
  details.cert = getCertData(cert);
  details.ca = getCertData(ca, true);

  var credentials = crypto.createCredentials(details);

  return credentials.context;
}

//
// https://stackoverflow.com/questions/18052919/javascript-regular-expression-to-add-protocol-to-url-string/18053700#18053700
// Adds http protocol if non specified.
function setHttp(link) {
  if (link.search(/^http[s]?\:\/\//) == -1) {
    link = 'http://' + link;
  }
  return link;
}

module.exports = ReverseProxy;
<commit_msg>check that writeHead is defined on the res object.<commit_after>"use strict";

var
  http = require('http'),
  httpProxy = require('http-proxy'),
  validUrl = require('valid-url'),
  parse_url = require('url').parse,
  path = require('path'),
  _ = require('lodash'),
  bunyan = require('bunyan');

function ReverseProxy(opts){
  if(!(this instanceof ReverseProxy)){
    return new ReverseProxy(opts);
  }

  opts = opts || {};
  opts.port = opts.port || 8080;

  var log;
  if(opts.bunyan != false){
    log = this.log = bunyan.createLogger(opts.bunyan || {
      name: 'redbird'
    });
  }

  var _this = this;

  //
  // Routing table.
  //
  var routing = this.routing = {};

  //
  // Create a proxy server with custom application logic
  //
  var proxy = this.proxy = httpProxy.createProxyServer({
    xfwd: true,
    prependPath: false
  });

  proxy.on('proxyReq', function(p, req, res, options) {
    if (req.host != null) {
      p.setHeader('host', req.host);
    }
  });

  //
  // Standard HTTP Proxy Server.
  //
  var server = this.server = require('http').createServer(function(req, res) {
    var src = getSource(req);
    var target = _this._getTarget(src, req);
    if(target){
      //
      // Automatically redirect to the HTTPS proxy if there are
      // certificates for this hostname.
      //
      if(certs && src in certs && target.sslRedirect){
        req.url = req._url || req.url; // Get the original url since we are going to redirect.
        redirectToHttps(req, res, target, opts.ssl, log);
      }else{
        proxy.web(req, res, {target: target});
      }
    }else {
      notFound(res);
    }
  });

  //
  // Listen to the `upgrade` event and proxy the
  // WebSocket requests as well.
  //
  server.on('upgrade', websocketsUpgrade);

  server.on('error', function(err){
    log && log.error(err, "Server Error");
  })

  //
  // Optionally create an https proxy server.
  //
  if(opts.ssl){
    var https = require('https');
    var certs = this.certs = {};

    var ssl = {
      SNICallback: function(hostname){
        return certs[hostname];
      },
      //
      // Default certs for clients that do not support SNI.
      //
      key: getCertData(opts.ssl.key),
      cert: getCertData(opts.ssl.cert)
    }

    if(opts.ssl.ca){
      ssl.ca = getCertData(opts.ssl.ca, true);
    }

    if(opts.ssl.opts){
      ssl = _.defaults(ssl, opts.ssl.opts);
    }

    var httpsServer = this.httpsServer = https.createServer(ssl, function(req, res){

      var src = getSource(req);

      var target = _this._getTarget(src, req);
      if(target){
        proxy.web(req, res, {target: target});
      }else {
        notFound(res);
      }
    });

    httpsServer.on('upgrade', websocketsUpgrade);

    httpsServer.on('error', function(err){
      log && log.error(err, "HTTPS Server Error");
    });

    httpsServer.on('clientError', function(err){
      log && log.error(err, "HTTPS Client  Error");
    });

    log && log.info("Listening to HTTPS requests on port %s", opts.ssl.port);
    httpsServer.listen(opts.ssl.port);
  }

  function websocketsUpgrade(req, socket, head){
    var src = getSource(req);
    var target = _this._getTarget(src, req);
    log && log.info({headers: req.headers, target: target}, "upgrade to websockets");
    if(target){
      proxy.ws(req, socket, head, {target: target});
    }else{
      notFound(socket);
    }
  }

  proxy.on('error', function(err, req, res){
    //
    // Send a 500 http status if headers have been sent
    //
    if (!res.headersSent) {
      res.writeHead && res.writeHead(500);
    }

    //
    // Do not log this common error
    //
    if(err.message !== 'socket hang up'){
      log && log.error(err, "Proxy Error");
    }
  })

  server.listen(opts.port);

  log && log.info(opts.port, "Started a Redbird reverse proxy server");
}

/**
  Register a new route.

  @src {String|URL} A string or a url parsed by node url module.
  Note that port is ignored, since the proxy just listens to one port.

  @target {String|URL} A string or a url parsed by node url module.
  @opts {Object} Route options.
*/
ReverseProxy.prototype.register = function(src, target, opts){
  if(!src || !target){
    throw Error("Cannot register a new route with unspecified src or target");
  }

  var routing = this.routing;

  src = prepareUrl(src);
  target = prepareUrl(target);

  target.sslRedirect = true;
  target.useTargetHostHeader = false;

  if(opts){
    if(opts.ssl){
      if(!this.httpsServer){
        throw Error("Cannot register https routes without defining a ssl port");
      }

      target.sslRedirect = opts.ssl.redirect === false ? false : true;

      if(!this.certs[src.hostname]){
        if(opts.ssl.key || opts.ssl.cert || opts.ssl.ca){
          var cert = createCredentialContext(opts.ssl.key, opts.ssl.cert, opts.ssl.ca);
          this.certs[src.hostname] = cert;
        }else{
          // Trigger the use of the default certificates.
          this.certs[src.hostname] = undefined;
        }
      }
    }
    target.useTargetHostHeader = opts.useTargetHostHeader === true ? true : false;
  }

  var host = routing[src.hostname] = routing[src.hostname] || [];
  var pathname = src.pathname || '/';
  var route = _.find(host, {path: pathname});

  if(!route){
    route = {path: pathname, rr: 0, urls: []};
    host.push(route);

    //
    // Sort routes
    //
    routing[src.hostname] = _.sortBy(host, function(route){
      return -route.path.length;
    });
  }

  route.urls.push(target);

  this.log && this.log.info({from: src, to: target}, "Registered a new route");
}

ReverseProxy.prototype.unregister = function(src, target){
  if(!src) return;

  src = prepareUrl(src);
  var routes = this.routing[src.hostname] || [];
  var pathname = src.pathname || '/';
  var i;

  for(i=0; i<routes.length; i++){
    if(routes[i].path == pathname){
      break;
    }
  }

  if(i < routes.length){
    var route = routes[i];

    if(target){
      target = prepareUrl(target);
      _.remove(route.urls, function(url){
        return url.href == target.href;
      });
    }else{
      route.urls = []
    }

    if(route.urls.length == 0){
      routes.splice(i, 1);
    }

    this.log && this.log.info({from: src, to: target}, "Unregistered a route");
  }
}

ReverseProxy.prototype.resolve = function(host, url){
  // Given a src resolve it to a target route if any available.
  if(!host) return;

  url = url || '/';

  var routes = this.routing[host];
  var i = 0, path;

  if(routes){
    var len = routes.length;

    //
    // Find path that matches the start of req.url
    //
    for(i=0; i<len; i++){
      var route = routes[i];
      if(startsWith(url, route.path)){
        return route;
      }
    }
  }
}

ReverseProxy.prototype._getTarget = function(src, req){
  var url = req.url;
  var route = this.resolve(src, url);

  if(!route) {
    this.log && this.log.warn(src, 'no valid route found for given source')
    return;
  }

  var pathname = route.path;
  if(pathname.length > 1){
    //
    // remove prefix from src
    //
    req._url = url; // save original url
    req.url = url.substr(pathname.length) || '/'
  }

  //
  // Perform Round Robin on the available targets
  //
  var urls = route.urls;
  var j = route.rr;
  route.rr = (j + 1) % urls.length; // get and update Round robin index.
  var target = route.urls[j];

  //
  // Fix request url if targetname specified.
  //
  if(target.pathname){
    req.url = path.join(target.pathname, req.url);
  }

  //
  // Host headers are passed through from the source by default
  // Often we want to use the host header of the target instead
  //
  if (target.useTargetHostHeader === true) {
    req.host = target.host;
  }

  this.log && this.log.info("Proxying %s to %s", src + url, path.join(target.host, req.url))

  return target;
}

ReverseProxy.prototype.close = function(){
  try{
    this.server.close();
    this.httpsServer && this.httpsServer.close();
  }catch(err){
    // Ignore for now...
  }
}

//
// Helpers
//
function getSource(req){
  if(req.headers.host){
    return req.headers.host.split(':')[0]
  }
}

/**
  Routing table structure. An object with hostname as key, and an array as value.
  The array has one element per path associated to the given hostname.
  Every path has a RoundRobin value (rr) and urls array, with all the urls available
  for this target route.

  {
    hostA :
      [
        {
          path: '/',
          rr: 3,
          urls: []
        }
      ]
  }
*/

function notFound(res){
  res.write("Not Found");
  res.statusCode = 404;
  res.end();
}

//
// Redirect to the HTTPS proxy
//
function redirectToHttps(req, res, target, ssl, log){
  var hostname = req.headers.host.split(':')[0] + ':' + (ssl.redirectPort || ssl.port);
  var url = 'https://'+path.join(hostname, req.url);
  log && log.info("Redirecting %s to %s", path.join(req.headers.host, req.url), url);
  //
  // We can use 301 for permanent redirect, but its bad for debugging, we may have it as
  // a configurable option.
  //
  res.writeHead(302, {Location: url});
  res.end();
}

function startsWith(input, str){
  return input.slice(0, str.length) == str;
}

function prepareUrl(url){
  if(_.isString(url)){
    url = setHttp(url);

    if(!validUrl.isHttpUri(url)){
      throw Error('uri is not a valid http uri ' + url);
    }

    url = parse_url(url);
  }
  return url;
}

function getCertData(pathname, unbundle){
  var fs = require('fs');

  // TODO: Support input as Buffer, Stream or Pathname.

  if(pathname){
    if(_.isArray(pathname)){
      var pathnames = pathname;
      return _.flatten(_.map(pathnames, function(pathname){
        return getCertData(pathname, unbundle);
      }));
    }else if(fs.existsSync(pathname)){
      if(unbundle){
        return unbundleCert(fs.readFileSync(pathname, 'utf8'));
      }else{
        return fs.readFileSync(pathname, 'utf8');
      }
    }
  }
}

/**
  Unbundles a file composed of several certificates.
  http://www.benjiegillam.com/2012/06/node-dot-js-ssl-certificate-chain/
*/
function unbundleCert(bundle){
  var chain = bundle.trim().split("\n");

  var ca = [];
  var cert = [];

  for (var i = 0, len = chain.length; i < len; i++) {
    var line = chain[i].trim();
    if (!(line.length !== 0)) {
      continue;
    }
    cert.push(line);
    if (line.match(/-END CERTIFICATE-/)) {
      var joined = cert.join("\n");
      ca.push(joined);
      cert = [];
    }
  }
  return ca;
}

function createCredentialContext(key, cert, ca) {
  var crypto = require('crypto');

  var details = {};

  details.key = getCertData(key);
  details.cert = getCertData(cert);
  details.ca = getCertData(ca, true);

  var credentials = crypto.createCredentials(details);

  return credentials.context;
}

//
// https://stackoverflow.com/questions/18052919/javascript-regular-expression-to-add-protocol-to-url-string/18053700#18053700
// Adds http protocol if non specified.
function setHttp(link) {
  if (link.search(/^http[s]?\:\/\//) == -1) {
    link = 'http://' + link;
  }
  return link;
}

module.exports = ReverseProxy;
<|endoftext|>


<commit_before>import fetch from 'isomorphic-fetch'

export const REQUEST_FORM = 'REQUEST_FORM'
export const RECEIVE_FORM = 'RECEIVE_FORM'

function requestForm(name) {
  return {
    type: REQUEST_FORM,
    name
  }
}

function receiveForm(name, json) {
  return {
    type: RECEIVE_FORM,
    name,
    form: json.form,
    receivedAt: Date.now()
  }
}

export function fetchForm(name) {
  return dispatch => {
    dispatch(requestForm(name))
    return fetch(`http://localhost:8080/nice2/rest/forms/${name}`)
      .then(response => response.json())
      .then(json => dispatch(receiveForm(name, json)))
  }
}

const ACTION_HANDLERS = {
  [RECEIVE_FORM]: (forms, { name, form }) => {
    return Object.assign({}, forms, { [name]: form })
  }
}

const initialState = {}

export default function formsReducer(state = initialState, action: Action) {
  const handler = ACTION_HANDLERS[action.type]
  return handler ? handler(state, action) : state
}
<commit_msg>Only fetch form if not already present<commit_after>import fetch from 'isomorphic-fetch'

export const REQUEST_FORM = 'REQUEST_FORM'
export const RECEIVE_FORM = 'RECEIVE_FORM'

function requestForm(name) {
  return {
    type: REQUEST_FORM,
    name
  }
}

function receiveForm(name, json) {
  return {
    type: RECEIVE_FORM,
    name,
    form: json.form,
    receivedAt: Date.now()
  }
}

export function fetchForm(name) {
  return (dispatch, getState) => {
    if (getState().forms[name]) {
      return null
    }
    dispatch(requestForm(name))
    return fetch(`http://localhost:8080/nice2/rest/forms/${name}`)
      .then(response => response.json())
      .then(json => dispatch(receiveForm(name, json)))
  }
}

const ACTION_HANDLERS = {
  [RECEIVE_FORM]: (forms, { name, form }) => {
    return Object.assign({}, forms, { [name]: form })
  }
}

const initialState = {}

export default function formsReducer(state = initialState, action: Action) {
  const handler = ACTION_HANDLERS[action.type]
  return handler ? handler(state, action) : state
}
<|endoftext|>


<commit_before>var width = 960,
    height = 1160;

var projection = d3.geo.albers()
	.center([0, 55.4])
	.rotate([4.4, 0])
	.parallels([50, 50])
	.scale(1200*5)
	.translate([width/2, height/2]);

var path = d3.geo.path()
	.projection(projection);

var svg = d3.select("div#viz").append("svg")
	.attr("width", width)
	.attr("height", height);

d3.json("uk-postcode-area.json", function(error, uk) {
	svg.selectAll(".subunit")
		.data(topojson.feature(uk, uk.objects['uk-postcode-area']).features)
		.enter()
		.append("path")
		.attr("class", "feature")
		.attr("d", path);

});
<commit_msg>Adds visible boundaries to postcode (PC) areas<commit_after>var width = 960,
    height = 1160;

var projection = d3.geo.albers()
	.center([0, 55.4])
	.rotate([4.4, 0])
	.parallels([50, 50])
	.scale(1200*5)
	.translate([width/2, height/2]);

var path = d3.geo.path()
	.projection(projection);

var svg = d3.select("div#viz").append("svg")
	.attr("width", width)
	.attr("height", height);

d3.json("uk-postcode-area.json", function(error, uk) {
	svg.selectAll(".subunit")
		.data(topojson.feature(uk, uk.objects['uk-postcode-area']).features)
		.enter()
		.append("path")
		.attr("class", "feature")
		.attr("d", path);

	// Add boundary detection using a topojson mesh

	svg.append("path")
		.datum(topojson.mesh(uk, uk.objects['uk-postcode-area'], function(a,b) { return a!==b;}))
		.attr("class", "mesh")
		.attr("d", path);
	d3.select(".mesh")
		.attr("fill", "none")
		.attr("stroke", "#fff")
		.attr("stroke-width", ".5px")
		.attr("stroke-linejoin", "round");
});

<|endoftext|>


<commit_before>'use strict';

var net = require('net');
var url = require('url');
var http2 = require('http2');
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var reconnect = require('reconnect-net');

class Proxy {
    constructor(options, dns) {
        this.options = options;
        this.dns = dns;
        this.connections = new Map();

        this.server = net.createServer((socket) => {
            let requestData = '';
            let heartbeatInterval = undefined;
            let myDomain = undefined;

            socket.on('data', (data) => {
                requestData += data.toString('utf-8');

                try {
                    var result = JSON.parse(requestData);
                } catch (err) {
                    return;
                }

                if (result.domain) {
                    socket.removeAllListeners('data');

                    this.dns.kvPut(result.domain, this.localAddress, (err, key, n) => {
                        if (err) {
                            console.log('store dns failed:', err);
                            socket.write(JSON.stringify({ code: 2 }), 'utf-8');
                            socket.destroy();
                            return;
                        }

                        myDomain = result.domain;
                        this.connections.set(myDomain, socket);

                        heartbeatInterval =
                            setInterval(() => {
                                this.dns.kvPut(myDomain, this.localAddress, (err, key, n) => {
                                    if (err) {
                                        console.log('keep heartbeat interval failed:', err);
                                    }
                                });

                                let heartbeatRequest = http2.raw.request({
                                    host: myDomain,
                                    plain: true,
                                    socket: socket,
                                    path: '/',
                                    method: 'GET'
                                }, (resp) => {
                                    console.log('heartbeat response code:', resp.statusCode, 'host', myDomain);
                                });

                                heartbeatRequest.on('error', (error) => {
                                    console.log('heartbeat request error:', error, 'host', myDomain);
                                });
                            }, this.options.heartbeatInterval);

                        socket.write(JSON.stringify({ code: 0 }), 'utf-8');

                        console.log('new proxy connection:', myDomain);
                    });
                } else {
                    socket.write(JSON.stringify({ code: 1 }), 'utf-8');
                    socket.destroy();
                }
            });

            socket.on('error', (error) => {
                if (heartbeatInterval) clearInterval(heartbeatInterval);

                if (myDomain) {
                    http2.globalAgent.removeEndpoint({host: myDomain, plain: true});

                    this.connections.delete(myDomain);
                }
            });

            socket.on('close', () => {
                if (heartbeatInterval) clearInterval(heartbeatInterval);

                if (myDomain) {
                    http2.globalAgent.removeEndpoint({host: myDomain, plain: true});

                    this.connections.delete(myDomain);
                }

                console.log('proxy connection closed:', myDomain);
            });
        });

        if (options.entryNode && options.entryNode.proxyPort) {
            let reconnectFun = (stream) => {
                let signin = {
                    domain: options.domain
                };
                stream.write(JSON.stringify(signin), 'utf-8');

                let resultData = '';
                stream.on('data', (data) => {
                    resultData += data.toString('utf-8');

                    try {
                        var result = JSON.parse(resultData);
                    } catch (err) {
                        return;
                    }

                    if (result.code === 0) {
                        stream.removeAllListeners('data');

                        let heartbeatTimeoutFun = () => {
                            this.reconnectInstance.disconnect();

                            this.reconnectInstance =
                                reconnect(reconnectFun)
                                .on('error', (err) => {
                                    this.emit('error', err);
                                })
                                .connect(options.entryNode.proxyPort, options.entryNode.host);
                        };

                        this.heartbeatTimeout = setTimeout(heartbeatTimeoutFun, 2 * this.options.heartbeatInterval);

                        http2.raw.createServer({
                            plain: true,
                            createServer: (start) => {
                                start(stream);
                                return stream;
                            }
                        }, (request, response) => {
                            if (request.method === 'GET' && request.url === '/') {
                                // heartbeat
                                clearTimeout(this.heartbeatTimeout);
                                this.heartbeatTimeout = setTimeout(heartbeatTimeoutFun, 2 * this.options.heartbeatInterval);

                                response.end();
                                return;
                            }

                            this.emit('request', request, response);
                        });

                        this.emit('connected');
                    } else {
                        this.emit('error', {
                            errno: 'entry node error',
                            code: result.code
                        });
                        stream.destroy();
                    }
                });
            };

            this.reconnectInstance =
                reconnect(reconnectFun)
                .on('error', (err) => {
                    this.emit('error', err);
                })
                .connect(options.entryNode.proxyPort, options.entryNode.host);
        }
    }

    listen(port, cb) {
        this.server.listen(port, cb);
    }

    destroy(cb) {
        if (this.reconnectInstance) {
            if (this.heartbeatTimeout) clearTimeout(this.heartbeatTimeout);

            this.reconnectInstance.disconnect();
        }

        this.server.close(cb);
    }

    handleRequest(hostname, request, response) {
        if (hostname === this.options.domain) {
            this.emit('request', request, response);
        } else if (this.connections.has(hostname)) {
            let connection = this.connections.get(hostname);

            console.log('reverse request from', hostname);

            let reqUrl = url.parse(request.url);
            delete request.headers.host;
            delete request.headers.connection;

			let reverseRequest = http2.raw.request({
                host: hostname,
				plain: true,
				socket: connection,
				path: reqUrl.path,
                headers: request.headers,
				method: request.method
			}, (resp) => {
                response.writeHead(resp.statusCode, resp.headers);
				resp.pipe(response);
            });

			reverseRequest.on('error', (error) => {
				console.log('reverse request error:', error);

				response.statusCode = 500;
				response.end('internal error');
            });

			request.pipe(reverseRequest);
        } else {
            response.statusCode = 404;
            response.end(hostname + ' not found');
        }
    }
}

util.inherits(Proxy, EventEmitter);

module.exports = Proxy;<commit_msg>clear timeout when reconnect<commit_after>'use strict';

var net = require('net');
var url = require('url');
var http2 = require('http2');
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var reconnect = require('reconnect-net');

class Proxy {
    constructor(options, dns) {
        this.options = options;
        this.dns = dns;
        this.connections = new Map();

        this.server = net.createServer((socket) => {
            let requestData = '';
            let heartbeatInterval = undefined;
            let myDomain = undefined;

            socket.on('data', (data) => {
                requestData += data.toString('utf-8');

                try {
                    var result = JSON.parse(requestData);
                } catch (err) {
                    return;
                }

                if (result.domain) {
                    socket.removeAllListeners('data');

                    this.dns.kvPut(result.domain, this.localAddress, (err, key, n) => {
                        if (err) {
                            console.log('store dns failed:', err);
                            socket.write(JSON.stringify({ code: 2 }), 'utf-8');
                            socket.destroy();
                            return;
                        }

                        myDomain = result.domain;
                        this.connections.set(myDomain, socket);

                        heartbeatInterval =
                            setInterval(() => {
                                this.dns.kvPut(myDomain, this.localAddress, (err, key, n) => {
                                    if (err) {
                                        console.log('keep heartbeat interval failed:', err);
                                    }
                                });

                                let heartbeatRequest = http2.raw.request({
                                    host: myDomain,
                                    plain: true,
                                    socket: socket,
                                    path: '/',
                                    method: 'GET'
                                }, (resp) => {
                                    console.log('heartbeat response code:', resp.statusCode, 'host', myDomain);
                                });

                                heartbeatRequest.on('error', (error) => {
                                    console.log('heartbeat request error:', error, 'host', myDomain);
                                });
                            }, this.options.heartbeatInterval);

                        socket.write(JSON.stringify({ code: 0 }), 'utf-8');

                        console.log('new proxy connection:', myDomain);
                    });
                } else {
                    socket.write(JSON.stringify({ code: 1 }), 'utf-8');
                    socket.destroy();
                }
            });

            socket.on('error', (error) => {
                if (heartbeatInterval) clearInterval(heartbeatInterval);

                if (myDomain) {
                    http2.globalAgent.removeEndpoint({host: myDomain, plain: true});

                    this.connections.delete(myDomain);
                }
            });

            socket.on('close', () => {
                if (heartbeatInterval) clearInterval(heartbeatInterval);

                if (myDomain) {
                    http2.globalAgent.removeEndpoint({host: myDomain, plain: true});

                    this.connections.delete(myDomain);
                }

                console.log('proxy connection closed:', myDomain);
            });
        });

        if (options.entryNode && options.entryNode.proxyPort) {
            let reconnectFun = (stream) => {
                let signin = {
                    domain: options.domain
                };
                stream.write(JSON.stringify(signin), 'utf-8');

                let resultData = '';
                stream.on('data', (data) => {
                    resultData += data.toString('utf-8');

                    try {
                        var result = JSON.parse(resultData);
                    } catch (err) {
                        return;
                    }

                    if (result.code === 0) {
                        stream.removeAllListeners('data');

                        let heartbeatTimeoutFun = () => {
                            this.reconnectInstance.disconnect();

                            this.reconnectInstance =
                                reconnect(reconnectFun)
                                .on('error', (err) => {
                                    this.emit('error', err);
                                })
                                .connect(options.entryNode.proxyPort, options.entryNode.host);
                        };

                        if (this.heartbeatTimeout) clearTimeout(this.heartbeatTimeout);
                        this.heartbeatTimeout = setTimeout(heartbeatTimeoutFun, 2 * this.options.heartbeatInterval);

                        http2.raw.createServer({
                            plain: true,
                            createServer: (start) => {
                                start(stream);
                                return stream;
                            }
                        }, (request, response) => {
                            if (request.method === 'GET' && request.url === '/') {
                                // heartbeat
                                clearTimeout(this.heartbeatTimeout);
                                this.heartbeatTimeout = setTimeout(heartbeatTimeoutFun, 2 * this.options.heartbeatInterval);

                                response.end();
                                return;
                            }

                            this.emit('request', request, response);
                        });

                        this.emit('connected');
                    } else {
                        this.emit('error', {
                            errno: 'entry node error',
                            code: result.code
                        });
                        stream.destroy();
                    }
                });
            };

            this.reconnectInstance =
                reconnect(reconnectFun)
                .on('error', (err) => {
                    this.emit('error', err);
                })
                .connect(options.entryNode.proxyPort, options.entryNode.host);
        }
    }

    listen(port, cb) {
        this.server.listen(port, cb);
    }

    destroy(cb) {
        if (this.reconnectInstance) {
            if (this.heartbeatTimeout) clearTimeout(this.heartbeatTimeout);

            this.reconnectInstance.disconnect();
        }

        this.server.close(cb);
    }

    handleRequest(hostname, request, response) {
        if (hostname === this.options.domain) {
            this.emit('request', request, response);
        } else if (this.connections.has(hostname)) {
            let connection = this.connections.get(hostname);

            console.log('reverse request from', hostname);

            let reqUrl = url.parse(request.url);
            delete request.headers.host;
            delete request.headers.connection;

			let reverseRequest = http2.raw.request({
                host: hostname,
				plain: true,
				socket: connection,
				path: reqUrl.path,
                headers: request.headers,
				method: request.method
			}, (resp) => {
                response.writeHead(resp.statusCode, resp.headers);
				resp.pipe(response);
            });

			reverseRequest.on('error', (error) => {
				console.log('reverse request error:', error);

				response.statusCode = 500;
				response.end('internal error');
            });

			request.pipe(reverseRequest);
        } else {
            response.statusCode = 404;
            response.end(hostname + ' not found');
        }
    }
}

util.inherits(Proxy, EventEmitter);

module.exports = Proxy;<|endoftext|>


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

var HeatGrid = function(el) {
  this.el = $(el);

  var rgb = function(r, g, b) {
    return 'rgb(' + parseInt(r) + ',' + parseInt(g) + ',' + parseInt(b) + ')';
  }

  var frac = function(minval, maxval, fraction) {
    return minval + fraction * (maxval - minval);
  }

  var gradient = function(mincolor, zerocolor, maxcolor,
                          ofs) {
    if (ofs == 0) {
      return zerocolor;
    } else if (ofs < 0) {
      return [frac(zerocolor[0], mincolor[0], -ofs/3),
              frac(zerocolor[1], mincolor[1], -ofs/3),
              frac(zerocolor[2], mincolor[2], -ofs/3)];
    } else if (ofs > 0) {
      return [frac(zerocolor[0], maxcolor[0], ofs/3),
              frac(zerocolor[1], maxcolor[1], ofs/3),
              frac(zerocolor[2], maxcolor[2], ofs/3)];
    }
  }

  this.draw = function(grid) {
    console.debug('heatgrid.draw', grid);
    this.el.html('
<canvas></canvas>' +
                 '

');
    var heatgrid = this.el.find('#heatgrid');
    heatgrid.css({
      position: 'relative',
      overflow: 'scroll',
      width: '100%',
      height: '100%',
    });
    var popover = this.el.find('#heatgrid-popover');
    popover.css({
      position: 'absolute',
      top: 0, left: 0,
      background: '#aaa',
      border: '1px dotted black',
      'white-space': 'pre'
    });
    var canvas = this.el.find('canvas');
    var xmult = parseInt(1000 / grid.headers.length);
    if (xmult < 1) xmult = 1;
    var xsize = grid.headers.length * xmult;
    var ysize = grid.data.length;
    canvas.attr({width: xsize, height: ysize});
    canvas.css({
      background: '#fff',
      width: '100%',
      height: ysize //'100%',
    });
    console.debug('heatgrid canvas size is: x y =', xsize, ysize);
    var ctx = canvas[0].getContext('2d');

    if (!grid.data.length || !grid.data[0].length) {
      return;
    }

    // TODO(apenwarr): offsetX/Y are flakey, use something else
    var movefunc = function(offX, offY) {
      var x = parseInt(offX / canvas.width() * grid.headers.length);
      var y = parseInt(offY / canvas.height() * grid.data.length);
      if (x > grid.headers.length || y > grid.data.length) return;
      var info = [];
      for (var i = 0; i < grid.headers.length; i++) {
        if (grid.types[i] != 'number') {
          info.push(grid.data[y][i]);
        } else {
          break;
        }
      }
      info.push(grid.headers[x]);
      info.push('value=' + grid.data[y][x]);

      popover.css({
        left: (x + 0.4) / grid.headers.length * canvas.width(),
        top: (y + 0.4) / grid.data.length * canvas.height(),
      });
      popover.text(info.join('\n'));
    };
    heatgrid.mousemove(function(ev) {
      var pos = canvas.position();
      movefunc(ev.pageX - pos.left, ev.pageY - pos.top);
    });
    heatgrid.mouseleave(function() {
      popover.hide();
    });
    heatgrid.mouseenter(function() {
      popover.show();
    });

    var total = 0, count = 0;
    for (var y = 0; y < grid.data.length; y++) {
      for (var x = 0; x < grid.data[y].length; x++) {
        if (grid.types[x] != 'number') continue;
        var cell = parseFloat(grid.data[y][x]);
        if (!isNaN(cell)) {
          total += cell;
          count++;
        }
      }
    }
    var avg = total / count;

    var tdiff = 0;
    for (var y = 0; y < grid.data.length; y++) {
      for (var x = 0; x < grid.data[y].length; x++) {
        if (grid.types[x] != 'number') continue;
        var cell = parseFloat(grid.data[y][x]);
        if (!isNaN(cell)) {
          tdiff += (cell - avg) * (cell - avg);
        }
      }
    }
    var stddev = Math.sqrt(tdiff / count);
    console.debug('total,count,mean,stddev = ', total, count, avg, stddev);

    var img = ctx.createImageData(xsize, ysize);
    for (var y = 0; y < grid.data.length; y++) {
      for (var x = 0; x < grid.data[y].length; x++) {
        if (grid.types[x] != 'number') continue;
        var cell = parseFloat(grid.data[y][x]);
        if (isNaN(cell)) continue;
        var ofs = stddev ? (cell - avg) / stddev : 3;
        var color = gradient([192,192,192], [192,192,255], [0,0,255], ofs);
        if (!color) continue;
        var pix = (y * xsize + x*xmult) * 4;
        for (var i = 0; i < xmult; i++) {
          img.data[pix + 0] = color[0];
          img.data[pix + 1] = color[1];
          img.data[pix + 2] = color[2];
          img.data[pix + 3] = 255;
          pix += 4;
        }
      }
    }
    ctx.putImageData(img, 0, 0);
  }
};
<commit_msg>heatgrid: keyboard bindings, highlight box, more viewable popover.<commit_after>/*
 * Copyright 2013 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

var HeatGrid = function(el) {
  this.el = $(el);

  var rgb = function(r, g, b) {
    return 'rgb(' + parseInt(r) + ',' + parseInt(g) + ',' + parseInt(b) + ')';
  }

  var frac = function(minval, maxval, fraction) {
    return minval + fraction * (maxval - minval);
  }

  var gradient = function(mincolor, zerocolor, maxcolor,
                          ofs) {
    if (ofs == 0) {
      return zerocolor;
    } else if (ofs < 0) {
      return [frac(zerocolor[0], mincolor[0], -ofs/3),
              frac(zerocolor[1], mincolor[1], -ofs/3),
              frac(zerocolor[2], mincolor[2], -ofs/3)];
    } else if (ofs > 0) {
      return [frac(zerocolor[0], maxcolor[0], ofs/3),
              frac(zerocolor[1], maxcolor[1], ofs/3),
              frac(zerocolor[2], maxcolor[2], ofs/3)];
    }
  }

  this.draw = function(grid) {
    console.debug('heatgrid.draw', grid);
    this.el.html('
<canvas></canvas>' +
		 '

' +
		 '

');
    var heatgrid = this.el.find('#heatgrid');
    heatgrid.css({
      position: 'relative',
      overflow: 'scroll',
      width: '100%',
      height: '100%',
    });
    var popover = this.el.find('#heatgrid-popover');
    popover.css({
      position: 'absolute',
      background: '#aaa',
      border: '1px dotted black',
      'white-space': 'pre'
    });
    var highlight = this.el.find('#heatgrid-highlight');
    highlight.css({
      position: 'absolute',
	  //background: 'rgba(255,192,192,16)',
      width: '3px',
      height: '3px',
      margin: '0',
      padding: '0',
      border: '1px solid red',
    });
    var canvas = this.el.find('canvas');
    var xmult = parseInt(1000 / grid.headers.length);
    if (xmult < 1) xmult = 1;
    var xsize = grid.headers.length * xmult;
    var ysize = grid.data.length;
    canvas.attr({width: xsize, height: ysize});
    canvas.css({
      background: '#fff',
      width: '100%',
      height: ysize
    });
    console.debug('heatgrid canvas size is: x y =', xsize, ysize);
    var ctx = canvas[0].getContext('2d');

    if (!grid.data.length || !grid.data[0].length) {
      return;
    }

    var lastPos = { x: 0, y: 0 };
    var movefunc = function(x, y) {
      if (x >= grid.headers.length) x = grid.headers.length - 1;
      if (y >= grid.data.length) y = grid.data.length - 1;
      if (x < 0) x = 0;
      if (y < 0) y = 0;
      lastPos.x = x;
      lastPos.y = y;
      var info = [];
      for (var i = 0; i < grid.headers.length; i++) {
        if (grid.types[i] != 'number') {
          info.push(grid.data[y][i]);
        } else {
          break;
        }
      }
      info.push(grid.headers[x]);
      info.push('value=' + grid.data[y][x]);

      var cx = x / grid.headers.length * canvas.width();
      var cy = y / grid.data.length * canvas.height();
      highlight.css({left: cx - 2, top: cy - 2});
      if (cx < canvas.width() / 2) {
	popover.css({
	  left: cx + 30,
	  right: 'auto'
	});
      } else {
	popover.css({
	  left: 'auto',
	  right: heatgrid[0].clientWidth - cx + 10
	});
      }
      if (cy < canvas.height() / 2) {
	popover.css({
	  top: cy + 10,
	  bottom: 'auto'
	});
      } else {
	popover.css({
	  top: 'auto',
	  bottom: heatgrid[0].clientHeight - cy + 10
	});
      }
      popover.text(info.join('\n'));
    };
    heatgrid.mousemove(function(ev) {
      var pos = canvas.position();
      var offX = ev.pageX - pos.left - 1;
      var offY = ev.pageY - pos.top - 1;
      var x = parseInt(offX / canvas.width() * grid.headers.length);
      var y = parseInt(offY / canvas.height() * grid.data.length);
      movefunc(x, y);
    });
    heatgrid.keydown(function(ev) {
      if (ev.which == 38) { // up
	movefunc(lastPos.x, lastPos.y - 1);
      } else if (ev.which == 40) { // down
	movefunc(lastPos.x, lastPos.y + 1);
      } else if (ev.which == 37) { // left
	movefunc(lastPos.x - 1, lastPos.y);
      } else if (ev.which == 39) { // right
	movefunc(lastPos.x + 1, lastPos.y);
      } else {
	return true; // propagate event forward
      }
      ev.stopPropagation();
      return false;
    });
    heatgrid.mouseleave(function() {
      popover.hide();
    });
    heatgrid.mouseenter(function() {
      heatgrid.focus(); // so that keyboard bindings work
      popover.show();
    });

    var total = 0, count = 0;
    for (var y = 0; y < grid.data.length; y++) {
      for (var x = 0; x < grid.data[y].length; x++) {
        if (grid.types[x] != 'number') continue;
        var cell = parseFloat(grid.data[y][x]);
        if (!isNaN(cell)) {
          total += cell;
          count++;
        }
      }
    }
    var avg = total / count;

    var tdiff = 0;
    for (var y = 0; y < grid.data.length; y++) {
      for (var x = 0; x < grid.data[y].length; x++) {
        if (grid.types[x] != 'number') continue;
        var cell = parseFloat(grid.data[y][x]);
        if (!isNaN(cell)) {
          tdiff += (cell - avg) * (cell - avg);
        }
      }
    }
    var stddev = Math.sqrt(tdiff / count);
    console.debug('total,count,mean,stddev = ', total, count, avg, stddev);

    var img = ctx.createImageData(xsize, ysize);
    for (var y = 0; y < grid.data.length; y++) {
      for (var x = 0; x < grid.data[y].length; x++) {
        if (grid.types[x] != 'number') continue;
        var cell = parseFloat(grid.data[y][x]);
        if (isNaN(cell)) continue;
        var ofs = stddev ? (cell - avg) / stddev : 3;
        var color = gradient([192,192,192], [192,192,255], [0,0,255], ofs);
        if (!color) continue;
        var pix = (y * xsize + x*xmult) * 4;
        for (var i = 0; i < xmult; i++) {
          img.data[pix + 0] = color[0];
          img.data[pix + 1] = color[1];
          img.data[pix + 2] = color[2];
          img.data[pix + 3] = 255;
          pix += 4;
        }
      }
    }
    ctx.putImageData(img, 0, 0);
  }
};
<|endoftext|>


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

import { defineMessages } from 'react-intl';
import { normalize } from 'normalizr';
import { startSubmit, stopSubmit } from 'redux-form';
import yaml from 'js-yaml';

import EnvironmentConfigurationConstants from '../constants/EnvironmentConfigurationConstants';
import { handleErrors } from './ErrorActions';
import MistralApiService from '../services/MistralApiService';
import NotificationActions from '../actions/NotificationActions';
import { topicSchema } from '../normalizrSchemas/environmentConfiguration';
import MistralConstants from '../constants/MistralConstants';
import SwiftApiService from '../services/SwiftApiService';

const messages = defineMessages({
  envConfigUpdatedNotificationMessage: {
    id: 'EnvironmentConfigurationActions.envConfigUpdatedNotificationMessage',
    defaultMessage:
      'The Environment Configuration has been successfully updated.'
  },
  envConfigUpdatedNotificationTitle: {
    id: 'EnvironmentConfigurationActions.envConfigUpdatedNotificationTitle',
    defaultMessage: 'Environment Configuration updated'
  },
  configurationNotUpdatedError: {
    id: 'EnvironmentConfigurationActions.configurationNotUpdatedError',
    defaultMessage: 'Deployment configuration could not be updated'
  }
});

export default {
  fetchEnvironmentConfiguration(planName, redirect) {
    return dispatch => {
      dispatch(this.fetchEnvironmentConfigurationPending());
      return dispatch(
        MistralApiService.runAction(MistralConstants.CAPABILITIES_GET, {
          container: planName
        })
      )
        .then(response => {
          const entities = normalize(response, [topicSchema]).entities || {};
          dispatch(this.fetchEnvironmentConfigurationSuccess(entities));
        })
        .catch(error => {
          if (redirect) {
            redirect();
          }
          dispatch(
            handleErrors(error, 'Deployment configuration could not be loaded')
          );
          dispatch(this.fetchEnvironmentConfigurationFailed());
        });
    };
  },

  fetchEnvironmentConfigurationPending() {
    return {
      type:
        EnvironmentConfigurationConstants.FETCH_ENVIRONMENT_CONFIGURATION_PENDING
    };
  },

  fetchEnvironmentConfigurationSuccess(entities) {
    return {
      type:
        EnvironmentConfigurationConstants.FETCH_ENVIRONMENT_CONFIGURATION_SUCCESS,
      payload: entities
    };
  },

  fetchEnvironmentConfigurationFailed(environment) {
    return {
      type:
        EnvironmentConfigurationConstants.FETCH_ENVIRONMENT_CONFIGURATION_FAILED
    };
  },

  updateEnvironmentConfiguration(planName, data, redirect) {
    return (dispatch, getState, { getIntl }) => {
      const { formatMessage } = getIntl(getState());
      dispatch(startSubmit('environmentConfigurationForm'));
      return dispatch(
        MistralApiService.runAction(MistralConstants.CAPABILITIES_UPDATE, {
          environments: data,
          container: planName
        })
      )
        .then(response => {
          const enabledEnvs = response.environments.map(env => env.path);
          dispatch(this.updateEnvironmentConfigurationSuccess(enabledEnvs));
          dispatch(stopSubmit('environmentConfigurationForm'));
          dispatch(
            NotificationActions.notify({
              title: formatMessage(messages.envConfigUpdatedNotificationTitle),
              message: formatMessage(
                messages.envConfigUpdatedNotificationMessage
              ),
              type: 'success'
            })
          );
          redirect && redirect();
        })
        .catch(error => {
          dispatch(
            stopSubmit('environmentConfigurationForm', {
              _error: {
                title: formatMessage(messages.configurationNotUpdatedError),
                message: error.message
              }
            })
          );
        });
    };
  },

  updateEnvironmentConfigurationSuccess(enabledEnvironments) {
    return {
      type:
        EnvironmentConfigurationConstants.UPDATE_ENVIRONMENT_CONFIGURATION_SUCCESS,
      payload: enabledEnvironments
    };
  },

  fetchEnvironment(planName, environmentPath) {
    return dispatch => {
      dispatch(this.fetchEnvironmentPending(environmentPath));
      dispatch(SwiftApiService.getObject(planName, environmentPath))
        .then(response => {
          const { resource_registry, parameter_defaults } = yaml.safeLoad(
            response,
            {
              filename: environmentPath,
              json: true
            }
          );
          dispatch(
            this.fetchEnvironmentSuccess({
              file: environmentPath,
              resourceRegistry: resource_registry,
              parameterDefaults: parameter_defaults
            })
          );
        })
        .catch(error => {
          dispatch(
            handleErrors(
              error,
              `Environment ${environmentPath} could not be loaded`,
              false
            )
          );
          dispatch(
            this.fetchEnvironmentFailed(environmentPath, {
              title: `Environment ${environmentPath} could not be loaded`,
              message: error.message
            })
          );
        });
    };
  },

  fetchEnvironmentPending(environmentPath) {
    return {
      type: EnvironmentConfigurationConstants.FETCH_ENVIRONMENT_PENDING,
      payload: environmentPath
    };
  },

  fetchEnvironmentSuccess(environment) {
    return {
      type: EnvironmentConfigurationConstants.FETCH_ENVIRONMENT_SUCCESS,
      payload: environment
    };
  },

  fetchEnvironmentFailed(environmentPath, error) {
    return {
      type: EnvironmentConfigurationConstants.FETCH_ENVIRONMENT_FAILED,
      payload: {
        environmentPath,
        error
      }
    };
  }
};
<commit_msg>Enable sorting of environments<commit_after>/**
 * Copyright 2017 Red Hat Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

import { defineMessages } from 'react-intl';
import { normalize } from 'normalizr';
import { startSubmit, stopSubmit } from 'redux-form';
import yaml from 'js-yaml';

import EnvironmentConfigurationConstants from '../constants/EnvironmentConfigurationConstants';
import { handleErrors } from './ErrorActions';
import MistralApiService from '../services/MistralApiService';
import NotificationActions from '../actions/NotificationActions';
import { topicSchema } from '../normalizrSchemas/environmentConfiguration';
import MistralConstants from '../constants/MistralConstants';
import SwiftApiService from '../services/SwiftApiService';

const messages = defineMessages({
  envConfigUpdatedNotificationMessage: {
    id: 'EnvironmentConfigurationActions.envConfigUpdatedNotificationMessage',
    defaultMessage:
      'The Environment Configuration has been successfully updated.'
  },
  envConfigUpdatedNotificationTitle: {
    id: 'EnvironmentConfigurationActions.envConfigUpdatedNotificationTitle',
    defaultMessage: 'Environment Configuration updated'
  },
  configurationNotUpdatedError: {
    id: 'EnvironmentConfigurationActions.configurationNotUpdatedError',
    defaultMessage: 'Deployment configuration could not be updated'
  }
});

export default {
  fetchEnvironmentConfiguration(planName, redirect) {
    return dispatch => {
      dispatch(this.fetchEnvironmentConfigurationPending());
      return dispatch(
        MistralApiService.runAction(MistralConstants.CAPABILITIES_GET, {
          container: planName
        })
      )
        .then(response => {
          const entities = normalize(response, [topicSchema]).entities || {};
          dispatch(this.fetchEnvironmentConfigurationSuccess(entities));
        })
        .catch(error => {
          if (redirect) {
            redirect();
          }
          dispatch(
            handleErrors(error, 'Deployment configuration could not be loaded')
          );
          dispatch(this.fetchEnvironmentConfigurationFailed());
        });
    };
  },

  fetchEnvironmentConfigurationPending() {
    return {
      type:
        EnvironmentConfigurationConstants.FETCH_ENVIRONMENT_CONFIGURATION_PENDING
    };
  },

  fetchEnvironmentConfigurationSuccess(entities) {
    return {
      type:
        EnvironmentConfigurationConstants.FETCH_ENVIRONMENT_CONFIGURATION_SUCCESS,
      payload: entities
    };
  },

  fetchEnvironmentConfigurationFailed(environment) {
    return {
      type:
        EnvironmentConfigurationConstants.FETCH_ENVIRONMENT_CONFIGURATION_FAILED
    };
  },

  updateEnvironmentConfiguration(planName, data, redirect) {
    return (dispatch, getState, { getIntl }) => {
      const { formatMessage } = getIntl(getState());
      dispatch(startSubmit('environmentConfigurationForm'));
      return dispatch(
        MistralApiService.runAction(MistralConstants.CAPABILITIES_UPDATE, {
          environments: data,
          container: planName,
          sort_environments: true
        })
      )
        .then(response => {
          const enabledEnvs = response.environments.map(env => env.path);
          dispatch(this.updateEnvironmentConfigurationSuccess(enabledEnvs));
          dispatch(stopSubmit('environmentConfigurationForm'));
          dispatch(
            NotificationActions.notify({
              title: formatMessage(messages.envConfigUpdatedNotificationTitle),
              message: formatMessage(
                messages.envConfigUpdatedNotificationMessage
              ),
              type: 'success'
            })
          );
          redirect && redirect();
        })
        .catch(error => {
          dispatch(
            stopSubmit('environmentConfigurationForm', {
              _error: {
                title: formatMessage(messages.configurationNotUpdatedError),
                message: error.message
              }
            })
          );
        });
    };
  },

  updateEnvironmentConfigurationSuccess(enabledEnvironments) {
    return {
      type:
        EnvironmentConfigurationConstants.UPDATE_ENVIRONMENT_CONFIGURATION_SUCCESS,
      payload: enabledEnvironments
    };
  },

  fetchEnvironment(planName, environmentPath) {
    return dispatch => {
      dispatch(this.fetchEnvironmentPending(environmentPath));
      dispatch(SwiftApiService.getObject(planName, environmentPath))
        .then(response => {
          const { resource_registry, parameter_defaults } = yaml.safeLoad(
            response,
            {
              filename: environmentPath,
              json: true
            }
          );
          dispatch(
            this.fetchEnvironmentSuccess({
              file: environmentPath,
              resourceRegistry: resource_registry,
              parameterDefaults: parameter_defaults
            })
          );
        })
        .catch(error => {
          dispatch(
            handleErrors(
              error,
              `Environment ${environmentPath} could not be loaded`,
              false
            )
          );
          dispatch(
            this.fetchEnvironmentFailed(environmentPath, {
              title: `Environment ${environmentPath} could not be loaded`,
              message: error.message
            })
          );
        });
    };
  },

  fetchEnvironmentPending(environmentPath) {
    return {
      type: EnvironmentConfigurationConstants.FETCH_ENVIRONMENT_PENDING,
      payload: environmentPath
    };
  },

  fetchEnvironmentSuccess(environment) {
    return {
      type: EnvironmentConfigurationConstants.FETCH_ENVIRONMENT_SUCCESS,
      payload: environment
    };
  },

  fetchEnvironmentFailed(environmentPath, error) {
    return {
      type: EnvironmentConfigurationConstants.FETCH_ENVIRONMENT_FAILED,
      payload: {
        environmentPath,
        error
      }
    };
  }
};
<|endoftext|>


<commit_before>'use strict';
var U = require('lodash');
var DynamoDB = require('./dynamodb');

function Query() {}

module.exports = Query;

U.extend(Query.prototype, {
	// spec.dynamodb
	// spec.tableName
	// spec.indexName
	// spec.hashkey
	// spec.rangekey
	// spec.rangeval
	// spec.rangeval2
	// spec.rangeExpression
	// spec.scanForward
	// spec.limit
	initialize: function (spec) {
		Object.defineProperties(this, {
			dynamodb: {
				value: spec.dynamodb
			},
			tableName: {
				enumerable: true,
				value: spec.tableName
			},
			indexName: {
				enumerable: true,
				value: spec.indexName || null
			},
			hashkey: {
				enumerable: true,
				value: spec.hashkey
			},
			rangekey: {
				enumerable: true,
				value: spec.rangekey
			},
			hashval: {
				enumerable: true,
				value: spec.hashval
			},
			rangeval: {
				enumerable: true,
				value: spec.rangeval
			},
			rangeval2: {
				enumerable: true,
				value: spec.rangeval2
			},
			rangeExpression: {
				enumerable: true,
				value: spec.rangeExpression || null
			},
			scanForward: {
				enumerable: true,
				value: U.has(spec, 'scanForward') ? spec.scanForward : true
			},
			limit: {
				enumerable: true,
				value: spec.limit || 20
			}
		});

		return this;
	},

	hashEqual: function (val) {
		return this.extend({
			hashval: val
		});
	},

	rangeEqual: function (val) {
		return this.extend({
			rangeval: val,
			rangeExpression: '#rangekey = :rangeval'
		});
	},

	rangeLessThan: function (val) {
		return this.extend({
			rangeval: val,
			rangeExpression: '#rangekey < :rangeval'
		});
	},

	rangeLessThanOrEqual: function (val) {
		return this.extend({
			rangeval: val,
			rangeExpression: '#rangekey <= :rangeval'
		});
	},

	rangeGreaterThan: function (val) {
		return this.extend({
			rangeval: val,
			rangeExpression: '#rangekey > :rangeval'
		});
	},

	rangeGreaterThanOrEqual: function (val) {
		return this.extend({
			rangeval: val,
			rangeExpression: '#rangekey >= :rangeval'
		});
	},

	rangeBetween: function (a, b) {
		return this.extend({
			rangeval: a,
			rangeval2: b,
			rangeExpression: '#rangekey BETWEEN :rangeval AND :rangeval2'
		});
	},

	rangeBeginsWith: function (val) {
		return this.extend({
			rangeval: val,
			rangeExpression: 'begins_with(#rangekey, :rangeval)'
		});
	},

	ascending: function () {
		return this.extend({
			scanForward: true
		});
	},

	descending: function () {
		return this.extend({
			scanForward: false
		});
	},

	limit: function (val) {
		return this.extend({
			limit: val
		});
	},

	// params.debug
	fetch: function (params) {
		params = params || Object.create(null);

		var attributeNames = {
			'#hashkey': this.hashkey
		};
		var values = {
			':hashval': DynamoDB.valueDefinition(this.hashval)
		};

		if (!U.isUndefined(this.rangeval)) {
			attributeNames['#rangekey'] = this.rangekey;
			values[':rangeval'] = DynamoDB.valueDefinition(this.rangeval);
		}
		if (!U.isUndefined(this.rangeval2)) {
			values[':rangeval2'] = DynamoDB.valueDefinition(this.rangeval2);
		}

		var expression = '#hashkey = :hashval';
		if (this.rangeExpression) {
			expression += (' AND ' + this.rangeExpression);
		}

		var newParams = {
			TableName: this.tableName,
			Select: 'ALL_ATTRIBUTES',
			KeyConditionExpression: expression,
			ScanIndexForward: this.scanForward,
			Limit: this.limit,
			// ExclusiveStartKey: startKey,
			ExpressionAttributeNames: attributeNames,
			ExpressionAttributeValues: values
			// Potentially useful parameters:
			// ReturnConsumedCapacity
		};

		if (this.indexName) {
			newParams.IndexName = this.indexName;
		}

		return this.dynamodb
			.query(newParams)
			.then(function deserializeData(res) {
				// { Items: [
				//   { id: { S: '41530' },
				//     issueNumber: { N: '0' },
				//     pageCount: { N: '136' },
				//     title: { S: 'Ant-Man: So (Trade Paperback)' },
				//     type: { S: 'Comic' },
				//     upc: { S: 'EMPTY' },
				//     description: { S: 'Its the origin of the original Avenger' },
				//     modified: { S: '2012-09-25T18:05:58-0400' } }
				//   ],
				//   Count: 20,
				//   ScannedCount: 20,
				//   LastEvaluatedKey:
				//    { type: { S: 'Comic' },
				//      id: { S: '55288' },
				//      modified: { S: '2015-04-02T15:50:47-0400' }
				//    }
				// }
				return res.Items.map(DynamoDB.deserializeData);
			});
	},

	extend: function (params) {
		// Copy existing properties to a new blank Object, then extend it with the
		// new params before passing into the constructor.
		var spec = U.extend(U.extend(Object.create(null), this), params);
		spec.dynamodb = this.dynamodb;
		return new Query(spec);
	}
});

// spec.dynamodb
// spec.tableName
// spec.indexName
// spec.hashkey
// spec.rangekey
Query.create = function (spec) {
	var obj = new Query();
	return obj.initialize(spec);
};
<commit_msg>Fix Query#extend()<commit_after>'use strict';
var U = require('lodash');
var DynamoDB = require('./dynamodb');

function Query() {}

module.exports = Query;

U.extend(Query.prototype, {
	// spec.dynamodb
	// spec.tableName
	// spec.indexName
	// spec.hashkey
	// spec.rangekey
	// spec.rangeval
	// spec.rangeval2
	// spec.rangeExpression
	// spec.scanForward
	// spec.limit
	initialize: function (spec) {
		Object.defineProperties(this, {
			dynamodb: {
				value: spec.dynamodb
			},
			tableName: {
				enumerable: true,
				value: spec.tableName
			},
			indexName: {
				enumerable: true,
				value: spec.indexName || null
			},
			hashkey: {
				enumerable: true,
				value: spec.hashkey
			},
			rangekey: {
				enumerable: true,
				value: spec.rangekey
			},
			hashval: {
				enumerable: true,
				value: spec.hashval
			},
			rangeval: {
				enumerable: true,
				value: spec.rangeval
			},
			rangeval2: {
				enumerable: true,
				value: spec.rangeval2
			},
			rangeExpression: {
				enumerable: true,
				value: spec.rangeExpression || null
			},
			scanForward: {
				enumerable: true,
				value: U.has(spec, 'scanForward') ? spec.scanForward : true
			},
			limit: {
				enumerable: true,
				value: spec.limit || 20
			}
		});

		return this;
	},

	hashEqual: function (val) {
		return this.extend({
			hashval: val
		});
	},

	rangeEqual: function (val) {
		return this.extend({
			rangeval: val,
			rangeExpression: '#rangekey = :rangeval'
		});
	},

	rangeLessThan: function (val) {
		return this.extend({
			rangeval: val,
			rangeExpression: '#rangekey < :rangeval'
		});
	},

	rangeLessThanOrEqual: function (val) {
		return this.extend({
			rangeval: val,
			rangeExpression: '#rangekey <= :rangeval'
		});
	},

	rangeGreaterThan: function (val) {
		return this.extend({
			rangeval: val,
			rangeExpression: '#rangekey > :rangeval'
		});
	},

	rangeGreaterThanOrEqual: function (val) {
		return this.extend({
			rangeval: val,
			rangeExpression: '#rangekey >= :rangeval'
		});
	},

	rangeBetween: function (a, b) {
		return this.extend({
			rangeval: a,
			rangeval2: b,
			rangeExpression: '#rangekey BETWEEN :rangeval AND :rangeval2'
		});
	},

	rangeBeginsWith: function (val) {
		return this.extend({
			rangeval: val,
			rangeExpression: 'begins_with(#rangekey, :rangeval)'
		});
	},

	ascending: function () {
		return this.extend({
			scanForward: true
		});
	},

	descending: function () {
		return this.extend({
			scanForward: false
		});
	},

	limit: function (val) {
		return this.extend({
			limit: val
		});
	},

	// params.debug
	fetch: function (params) {
		params = params || Object.create(null);

		var attributeNames = {
			'#hashkey': this.hashkey
		};
		var values = {
			':hashval': DynamoDB.valueDefinition(this.hashval)
		};

		if (!U.isUndefined(this.rangeval)) {
			attributeNames['#rangekey'] = this.rangekey;
			values[':rangeval'] = DynamoDB.valueDefinition(this.rangeval);
		}
		if (!U.isUndefined(this.rangeval2)) {
			values[':rangeval2'] = DynamoDB.valueDefinition(this.rangeval2);
		}

		var expression = '#hashkey = :hashval';
		if (this.rangeExpression) {
			expression += (' AND ' + this.rangeExpression);
		}

		var newParams = {
			TableName: this.tableName,
			Select: 'ALL_ATTRIBUTES',
			KeyConditionExpression: expression,
			ScanIndexForward: this.scanForward,
			Limit: this.limit,
			// ExclusiveStartKey: startKey,
			ExpressionAttributeNames: attributeNames,
			ExpressionAttributeValues: values
			// Potentially useful parameters:
			// ReturnConsumedCapacity
		};

		if (this.indexName) {
			newParams.IndexName = this.indexName;
		}

		return this.dynamodb
			.query(newParams)
			.then(function deserializeData(res) {
				// { Items: [
				//   { id: { S: '41530' },
				//     issueNumber: { N: '0' },
				//     pageCount: { N: '136' },
				//     title: { S: 'Ant-Man: So (Trade Paperback)' },
				//     type: { S: 'Comic' },
				//     upc: { S: 'EMPTY' },
				//     description: { S: 'Its the origin of the original Avenger' },
				//     modified: { S: '2012-09-25T18:05:58-0400' } }
				//   ],
				//   Count: 20,
				//   ScannedCount: 20,
				//   LastEvaluatedKey:
				//    { type: { S: 'Comic' },
				//      id: { S: '55288' },
				//      modified: { S: '2015-04-02T15:50:47-0400' }
				//    }
				// }
				return res.Items.map(DynamoDB.deserializeData);
			});
	},

	extend: function (params) {
		// Copy existing properties to a new blank Object, then extend it with the
		// new params before passing into the constructor.
		var spec = U.extend(U.extend(Object.create(null), this), params);
		spec.dynamodb = this.dynamodb;
		var obj = new Query();
		return obj.initialize(spec);
	}
});

// spec.dynamodb
// spec.tableName
// spec.indexName
// spec.hashkey
// spec.rangekey
Query.create = function (spec) {
	var obj = new Query();
	return obj.initialize(spec);
};
<|endoftext|>


<commit_before>export const start = {
  name: 'default',
  keywords: [],
  run () {
    return 'I don\'t understand what you mean, sir!';
  }
}

export const greet = {
  name: 'greet',
  keywords: [
    'hi',
    'hello'
  ],
  run () {
    return 'Hello';
  }
}

export const buy = {
  name: 'buy',
  keywords: [
    'buy'
  ],
  run () {
    return 'Buy';
  }
}

export const time = {
  name: 'time',
  keywords: [
    'what time is it'
  ],
  run () {
    return new Date();
  }
}
<commit_msg>keywords<commit_after>export const start = {
  name: 'default',
  keywords: [],
  run () {
    return 'I don\'t understand what you mean, sir!';
  }
}

export const greet = {
  name: 'greet',
  keywords: [
    'hi',
    'hello',
    'hey',
    'what up',
    'what\'s up',
    'how is it going'
  ],
  run () {
    return 'Hello';
  }
}

export const buy = {
  name: 'buy',
  keywords: [
    'buy'
  ],
  run () {
    return 'Buy';
  }
}

export const time = {
  name: 'time',
  keywords: [
    'what time is it'
  ],
  run () {
    return new Date();
  }
}
<|endoftext|>


<commit_before>
export const getDisplayName = component => component.displayName || component.name || 'Component';

export const ifNot = (condition, errorMessage) => {
  if (!condition) throw new Error(errorMessage);
};

/**
 * Return a component to be rendered by a routeNode for the current route
 * extracted from the custom (nested) routes definition (with 'component' field)
 * @param {array} routes - nested routes def (with 'component' field)
 * @param {object} routerStore - the mobx-router store. Used for getting the current route
 * @param {string} routeNode - the name of the route for the React component from where to re-render (transition node)
 * @returns {React.Component} - the component to be rendered
 */
export function getComponentFromRoutes(routes, routerStore, routeNode) {
  let level = 0;
  let currentLevel = 0;
  // Break current route in segments (levels)
  const routeSegments = routerStore.route.name.split('.');

  // Set nesting level where to find routes for this routeNode
  if (routeNode === '') level = 0;
  else level = routeNode.split('.').length;
  if (level === 0 && routeNode !== '') level = 1;

  // Recurse until it gets the relevant portion of the routes obj or the component itself
  function getComponent(routesObj) {
    for (const route of routesObj) {
      const segment = routeSegments[currentLevel]; // going deeper every recursion
      if (route.name === segment) {

        if (currentLevel >= level) { // Exit condition
          return route.component;
        }
        else {
          currentLevel += 1;
          return getComponent(route.children);
        }
      }
    }
  }

  return getComponent(routes);
}
<commit_msg>getComponentFromRoutes changes<commit_after>
export const getDisplayName = component => component.displayName || component.name || 'Component';

export const ifNot = (condition, errorMessage) => {
  if (!condition) throw new Error(errorMessage);
};

/**
 * Return a component to be rendered by a routeNode for the current route
 * extracted from the custom (nested) routes definition (with 'component' field)
 * @param {object} route - the current active route object
 * @param {string} routeNodeName - the name of the route for the React component from where to re-render (transition node)
 * @param {array} routesConfig - nested routes configuration object (with 'component' field)
 * @returns {React.Component} - the component to be rendered
 */
export function getComponentFromRoutes(route, routeNodeName, routesConfig) {
  let level = 0;
  let currentLevel = 0;
  // Break current route in segments (levels)
  const routeSegments = route.name.split('.');

  // Set nesting level where to find routes for this routeNode
  if (routeNodeName === '') level = 0;
  else level = routeNodeName.split('.').length;
  if (level === 0 && routeNodeName !== '') level = 1;

  // Recurse until it gets the relevant portion of the routes obj or the component itself
  function getComponent(routesConfig) {
    for (const route of routesConfig) {
      const segment = routeSegments[currentLevel]; // going deeper every recursion
      if (route.name === segment) {

        if (currentLevel >= level) { // Exit condition
          return route.component;
        }
        else {
          currentLevel += 1;
          return getComponent(route.children);
        }
      }
    }
  }

  return getComponent(routesConfig);
}
<|endoftext|>