<commit_before>//
// Superclass to be used by all of the main routes below.
//
App.BaseRoute = Ember.Route.extend({
  rootKey: '',
  condensedView: false,

  // Don't record characters in browser history
  // for the "search" query item (filter)
  queryParams: {
    filter: {
      replace: true
    }
  },

  getParentAndGrandparent: function(key) {
    var parentKey = this.rootKey,
        grandParentKey = this.rootKey,
        parts = key.split('/');

    if (parts.length > 0) {
      parts.pop();
      parentKey = parts.join("/") + "/";
    }

    if (parts.length > 1) {
      parts.pop();
      grandParentKey = parts.join("/") + "/";
    }

    return {
      parent: parentKey,
      grandParent: grandParentKey,
      isRoot: parentKey === '/'
    };
  },

  removeDuplicateKeys: function(keys, matcher) {
    // Loop over the keys
    keys.forEach(function(item, index) {
      if (item.get('Key') == matcher) {
      // If we are in a nested folder and the folder
      // name matches our position, remove it
        keys.splice(index, 1);
      }
    });
    return keys;
  },

  actions: {
    // Used to link to keys that are not objects,
    // like parents and grandParents
    linkToKey: function(key) {
      if (key == "/") {
        this.transitionTo('kv.show', "");
      }
      else if (key.slice(-1) === '/' || key === this.rootKey) {
        this.transitionTo('kv.show', key);
      } else {
        this.transitionTo('kv.edit', key);
      }
    }
  }
});

//
// The route for choosing datacenters, typically the first route loaded.
//
App.IndexRoute = App.BaseRoute.extend({
  // Retrieve the list of datacenters
  model: function(params) {
    return Ember.$.getJSON(consulHost + '/v1/catalog/datacenters').then(function(data) {
      return data;
    });
  },

  afterModel: function(model, transition) {
    // If we only have one datacenter, jump
    // straight to it and bypass the global
    // view
    if (model.get('length') === 1) {
      this.transitionTo('services', model[0]);
    }
  }
});

// The parent route for all resources. This keeps the top bar
// functioning, as well as the per-dc requests.
App.DcRoute = App.BaseRoute.extend({
  model: function(params) {
    var token = App.get('settings.token');

    // Return a promise hash to retreieve the
    // dcs and nodes used in the header
    return Ember.RSVP.hash({
      dc: params.dc,
      dcs: Ember.$.getJSON(consulHost + '/v1/catalog/datacenters'),
      nodes: Ember.$.getJSON(formatUrl(consulHost + '/v1/internal/ui/nodes', params.dc, token)).then(function(data) {
        var objs = [];

        // Merge the nodes into a list and create objects out of them
        data.map(function(obj){
          objs.push(App.Node.create(obj));
        });

        return objs;
      }),
      coordinates: Ember.$.getJSON(formatUrl(consulHost + '/v1/coordinate/nodes', params.dc, token)).then(function(data) {
        return data;
      })
    });
  },

  setupController: function(controller, models) {
    controller.set('content', models.dc);
    controller.set('nodes', models.nodes);
    controller.set('dcs', models.dcs);
    controller.set('coordinates', models.coordinates);
    controller.set('isDropdownVisible', false);
  },
});

App.KvIndexRoute = App.BaseRoute.extend({
  beforeModel: function() {
    this.transitionTo('kv.show', this.rootKey);
  }
});

App.KvShowRoute = App.BaseRoute.extend({
  model: function(params) {
    var key = params.key;
    var dc = this.modelFor('dc').dc;
    var token = App.get('settings.token');

    // Return a promise has with the ?keys for that namespace
    // and the original key requested in params
    return Ember.RSVP.hash({
      key: key,
      keys: Ember.$.getJSON(formatUrl(consulHost + '/v1/kv/' + key + '?keys&seperator=/', dc, token)).then(function(data) {
        var objs = [];
        data.map(function(obj){
          objs.push(App.Key.create({Key: obj}));
        });
        return objs;
      })
    });
  },

  setupController: function(controller, models) {
    var key = models.key;
    var parentKeys = this.getParentAndGrandparent(key);
    models.keys = this.removeDuplicateKeys(models.keys, models.key);

    controller.set('content', models.keys);
    controller.set('parentKey', parentKeys.parent);
    controller.set('grandParentKey', parentKeys.grandParent);
    controller.set('isRoot', parentKeys.isRoot);
    controller.set('newKey', App.Key.create());
    controller.set('rootKey', this.rootKey);
  }
});

App.KvEditRoute = App.BaseRoute.extend({
  model: function(params) {
    var key = params.key;
    var dc = this.modelFor('dc').dc;
    var parentKeys = this.getParentAndGrandparent(key);
    var token = App.get('settings.token');

    // Return a promise hash to get the data for both columns
    return Ember.RSVP.hash({
      dc: dc,
      token: token,
      key: Ember.$.getJSON(formatUrl(consulHost + '/v1/kv/' + key, dc, token)).then(function(data) {
        // Convert the returned data to a Key
        return App.Key.create().setProperties(data[0]);
      }),
      keys: keysPromise = Ember.$.getJSON(formatUrl(consulHost + '/v1/kv/' + parentKeys.parent + '?keys&seperator=/', dc, token)).then(function(data) {
        var objs = [];
        data.map(function(obj){
         objs.push(App.Key.create({Key: obj}));
        });
        return objs;
      }),
    });
  },

  // Load the session on the key, if there is one
  afterModel: function(models) {
    if (models.key.get('isLocked')) {
      return Ember.$.getJSON(formatUrl(consulHost + '/v1/session/info/' + models.key.Session, models.dc, models.token)).then(function(data) {
        models.session = data[0];
        return models;
      });
    } else {
      return models;
    }
  },

  setupController: function(controller, models) {
    var key = models.key;
    var parentKeys = this.getParentAndGrandparent(key.get('Key'));
    models.keys = this.removeDuplicateKeys(models.keys, parentKeys.parent);

    controller.set('content', models.key);
    controller.set('parentKey', parentKeys.parent);
    controller.set('grandParentKey', parentKeys.grandParent);
    controller.set('isRoot', parentKeys.isRoot);
    controller.set('siblings', models.keys);
    controller.set('rootKey', this.rootKey);
    controller.set('session', models.session);
  }
});

App.ServicesRoute = App.BaseRoute.extend({
  model: function(params) {
    var dc = this.modelFor('dc').dc;
    var token = App.get('settings.token');

    // Return a promise to retrieve all of the services
    return Ember.$.getJSON(formatUrl(consulHost + '/v1/internal/ui/services', dc, token)).then(function(data) {
      var objs = [];
      data.map(function(obj){
       objs.push(App.Service.create(obj));
      });
      return objs;
    });
  },
  setupController: function(controller, model) {
    controller.set('services', model);
  }
});

App.ServicesShowRoute = App.BaseRoute.extend({
  model: function(params) {
    var dc = this.modelFor('dc').dc;
    var token = App.get('settings.token');

    // Here we just use the built-in health endpoint, as it gives us everything
    // we need.
    return Ember.$.getJSON(formatUrl(consulHost + '/v1/health/service/' + params.name, dc, token)).then(function(data) {
      var objs = [];
      data.map(function(obj){
       objs.push(App.Node.create(obj));
      });
      return objs;
    });
  },
  setupController: function(controller, model) {
    var tags = [];
    model.map(function(obj){
      tags = tags.concat(obj.Service.Tags);
    });

    tags = tags.filter(function(n){ return n !== undefined; });
    tags = tags.uniq().join(', ');

    controller.set('content', model);
    controller.set('tags', tags);
  }
});

function distance(a, b) {
    a = a.Coord;
    b = b.Coord;
    var sum = 0;
    for (var i = 0; i < a.Vec.length; i++) {
        var diff = a.Vec[i] - b.Vec[i];
        sum += diff * diff;
    }
    var rtt = Math.sqrt(sum) + a.Height + b.Height;

    var adjusted = rtt + a.Adjustment + b.Adjustment;
    if (adjusted > 0.0) {
        rtt = adjusted;
    }

    return Math.round(rtt * 100000.0) / 100.0;
}

App.NodesShowRoute = App.BaseRoute.extend({
  model: function(params) {
    var dc = this.modelFor('dc');
    var token = App.get('settings.token');

    var min = 999999999;
    var max = -999999999;
    var sum = 0;
    var distances = [];
    dc.coordinates.forEach(function (node) {
      if (params.name == node.Node) {
        dc.coordinates.forEach(function (other) {
          if (node.Node != other.Node) {
            var dist = distance(node, other);
            distances.push({ node: other.Node, distance: dist });
            sum += dist;
            if (dist < min) {
              min = dist;
            }
            if (dist > max) {
              max = dist;
            }
          }
        });
        distances.sort(function (a, b) {
          return a.distance - b.distance;
        });
      }
    });
    var n = distances.length;
    var halfN = Math.floor(n / 2);
    var median;

    if (n > 0) {
      if (n % 2) {
        // odd
        median = distances[halfN].distance;
      } else {
        median = (distances[halfN - 1].distance + distances[halfN].distance) / 2;
      }
    } else {
      median = 0;
      min = 0;
      max = 0;
    }

    // Return a promise hash of the node and nodes
    return Ember.RSVP.hash({
      dc: dc.dc,
      token: token,
      tomography: {
        distances: distances,
        n: distances.length,
        min: parseInt(min * 100) / 100,
        median: parseInt(median * 100) / 100,
        max: parseInt(max * 100) / 100
      },
      node: Ember.$.getJSON(formatUrl(consulHost + '/v1/internal/ui/node/' + params.name, dc.dc, token)).then(function(data) {
        return App.Node.create(data);
      }),
      nodes: Ember.$.getJSON(formatUrl(consulHost + '/v1/internal/ui/node/' + params.name, dc.dc, token)).then(function(data) {
        return App.Node.create(data);
      })
    });
  },

  // Load the sessions for the node
  afterModel: function(models) {
    return Ember.$.getJSON(formatUrl(consulHost + '/v1/session/node/' + models.node.Node, models.dc, models.token)).then(function(data) {
      models.sessions = data;
      return models;
    });
  },

  setupController: function(controller, models) {
      controller.set('content', models.node);
      controller.set('sessions', models.sessions);
      controller.set('tomography', models.tomography);
      //
      // Since we have 2 column layout, we need to also display the
      // list of nodes on the left. Hence setting the attribute
      // {{nodes}} on the controller.
      //
      controller.set('nodes', models.nodes);
  }
});

App.NodesRoute = App.BaseRoute.extend({
  model: function(params) {
    var dc = this.modelFor('dc').dc;
    var token = App.get('settings.token');

    // Return a promise containing the nodes
    return Ember.$.getJSON(formatUrl(consulHost + '/v1/internal/ui/nodes', dc, token)).then(function(data) {
      var objs = [];
      data.map(function(obj){
       objs.push(App.Node.create(obj));
      });
      return objs;
    });
  },
  setupController: function(controller, model) {
    controller.set('nodes', model);
  }
});

App.AclsRoute = App.BaseRoute.extend({
  model: function(params) {
    var dc = this.modelFor('dc').dc;
    var token = App.get('settings.token');
    // Return a promise containing the ACLS
    return Ember.$.getJSON(formatUrl(consulHost + '/v1/acl/list', dc, token)).then(function(data) {
      var objs = [];
      data.map(function(obj){
        if (obj.ID === "anonymous") {
          objs.unshift(App.Acl.create(obj));
        } else {
          objs.push(App.Acl.create(obj));
        }
      });
      return objs;
    });
  },

  actions: {
    error: function(error, transition) {
      // If consul returns 401, ACLs are disabled
      if (error && error.status === 401) {
        this.transitionTo('dc.aclsdisabled');
      // If consul returns 403, they key isn't authorized for that
      // action.
      } else if (error && error.status === 403) {
        this.transitionTo('dc.unauthorized');
      }
      return true;
    }
  },

  setupController: function(controller, model) {
      controller.set('acls', model);
      controller.set('newAcl', App.Acl.create());
  }
});

App.AclsShowRoute = App.BaseRoute.extend({
  model: function(params) {
    var dc = this.modelFor('dc').dc;
    var token = App.get('settings.token');

    // Return a promise hash of the node and nodes
    return Ember.RSVP.hash({
      dc: dc,
      acl: Ember.$.getJSON(formatUrl(consulHost + '/v1/acl/info/'+ params.id, dc, token)).then(function(data) {
        return App.Acl.create(data[0]);
      })
    });
  },

  setupController: function(controller, models) {
      controller.set('content', models.acl);
  }
});

App.SettingsRoute = App.BaseRoute.extend({
  model: function(params) {
    return App.get('settings');
  }
});

// Adds any global parameters we need to set to a url/path
function formatUrl(url, dc, token) {
  if (token == null) {
    token = "";
  }
  if (url.indexOf("?") > 0) {
    // If our url has existing params
    url = url + "&dc=" + dc;
    url = url + "&token=" + token;
  } else {
    // Our url doesn't have params
    url = url + "?dc=" + dc;
    url = url + "&token=" + token;
  }
  return url;
}
<commit_msg>UI: remove redundant commas in tags list (services view)<commit_after>//
// Superclass to be used by all of the main routes below.
//
App.BaseRoute = Ember.Route.extend({
  rootKey: '',
  condensedView: false,

  // Don't record characters in browser history
  // for the "search" query item (filter)
  queryParams: {
    filter: {
      replace: true
    }
  },

  getParentAndGrandparent: function(key) {
    var parentKey = this.rootKey,
        grandParentKey = this.rootKey,
        parts = key.split('/');

    if (parts.length > 0) {
      parts.pop();
      parentKey = parts.join("/") + "/";
    }

    if (parts.length > 1) {
      parts.pop();
      grandParentKey = parts.join("/") + "/";
    }

    return {
      parent: parentKey,
      grandParent: grandParentKey,
      isRoot: parentKey === '/'
    };
  },

  removeDuplicateKeys: function(keys, matcher) {
    // Loop over the keys
    keys.forEach(function(item, index) {
      if (item.get('Key') == matcher) {
      // If we are in a nested folder and the folder
      // name matches our position, remove it
        keys.splice(index, 1);
      }
    });
    return keys;
  },

  actions: {
    // Used to link to keys that are not objects,
    // like parents and grandParents
    linkToKey: function(key) {
      if (key == "/") {
        this.transitionTo('kv.show', "");
      }
      else if (key.slice(-1) === '/' || key === this.rootKey) {
        this.transitionTo('kv.show', key);
      } else {
        this.transitionTo('kv.edit', key);
      }
    }
  }
});

//
// The route for choosing datacenters, typically the first route loaded.
//
App.IndexRoute = App.BaseRoute.extend({
  // Retrieve the list of datacenters
  model: function(params) {
    return Ember.$.getJSON(consulHost + '/v1/catalog/datacenters').then(function(data) {
      return data;
    });
  },

  afterModel: function(model, transition) {
    // If we only have one datacenter, jump
    // straight to it and bypass the global
    // view
    if (model.get('length') === 1) {
      this.transitionTo('services', model[0]);
    }
  }
});

// The parent route for all resources. This keeps the top bar
// functioning, as well as the per-dc requests.
App.DcRoute = App.BaseRoute.extend({
  model: function(params) {
    var token = App.get('settings.token');

    // Return a promise hash to retreieve the
    // dcs and nodes used in the header
    return Ember.RSVP.hash({
      dc: params.dc,
      dcs: Ember.$.getJSON(consulHost + '/v1/catalog/datacenters'),
      nodes: Ember.$.getJSON(formatUrl(consulHost + '/v1/internal/ui/nodes', params.dc, token)).then(function(data) {
        var objs = [];

        // Merge the nodes into a list and create objects out of them
        data.map(function(obj){
          objs.push(App.Node.create(obj));
        });

        return objs;
      }),
      coordinates: Ember.$.getJSON(formatUrl(consulHost + '/v1/coordinate/nodes', params.dc, token)).then(function(data) {
        return data;
      })
    });
  },

  setupController: function(controller, models) {
    controller.set('content', models.dc);
    controller.set('nodes', models.nodes);
    controller.set('dcs', models.dcs);
    controller.set('coordinates', models.coordinates);
    controller.set('isDropdownVisible', false);
  },
});

App.KvIndexRoute = App.BaseRoute.extend({
  beforeModel: function() {
    this.transitionTo('kv.show', this.rootKey);
  }
});

App.KvShowRoute = App.BaseRoute.extend({
  model: function(params) {
    var key = params.key;
    var dc = this.modelFor('dc').dc;
    var token = App.get('settings.token');

    // Return a promise has with the ?keys for that namespace
    // and the original key requested in params
    return Ember.RSVP.hash({
      key: key,
      keys: Ember.$.getJSON(formatUrl(consulHost + '/v1/kv/' + key + '?keys&seperator=/', dc, token)).then(function(data) {
        var objs = [];
        data.map(function(obj){
          objs.push(App.Key.create({Key: obj}));
        });
        return objs;
      })
    });
  },

  setupController: function(controller, models) {
    var key = models.key;
    var parentKeys = this.getParentAndGrandparent(key);
    models.keys = this.removeDuplicateKeys(models.keys, models.key);

    controller.set('content', models.keys);
    controller.set('parentKey', parentKeys.parent);
    controller.set('grandParentKey', parentKeys.grandParent);
    controller.set('isRoot', parentKeys.isRoot);
    controller.set('newKey', App.Key.create());
    controller.set('rootKey', this.rootKey);
  }
});

App.KvEditRoute = App.BaseRoute.extend({
  model: function(params) {
    var key = params.key;
    var dc = this.modelFor('dc').dc;
    var parentKeys = this.getParentAndGrandparent(key);
    var token = App.get('settings.token');

    // Return a promise hash to get the data for both columns
    return Ember.RSVP.hash({
      dc: dc,
      token: token,
      key: Ember.$.getJSON(formatUrl(consulHost + '/v1/kv/' + key, dc, token)).then(function(data) {
        // Convert the returned data to a Key
        return App.Key.create().setProperties(data[0]);
      }),
      keys: keysPromise = Ember.$.getJSON(formatUrl(consulHost + '/v1/kv/' + parentKeys.parent + '?keys&seperator=/', dc, token)).then(function(data) {
        var objs = [];
        data.map(function(obj){
         objs.push(App.Key.create({Key: obj}));
        });
        return objs;
      }),
    });
  },

  // Load the session on the key, if there is one
  afterModel: function(models) {
    if (models.key.get('isLocked')) {
      return Ember.$.getJSON(formatUrl(consulHost + '/v1/session/info/' + models.key.Session, models.dc, models.token)).then(function(data) {
        models.session = data[0];
        return models;
      });
    } else {
      return models;
    }
  },

  setupController: function(controller, models) {
    var key = models.key;
    var parentKeys = this.getParentAndGrandparent(key.get('Key'));
    models.keys = this.removeDuplicateKeys(models.keys, parentKeys.parent);

    controller.set('content', models.key);
    controller.set('parentKey', parentKeys.parent);
    controller.set('grandParentKey', parentKeys.grandParent);
    controller.set('isRoot', parentKeys.isRoot);
    controller.set('siblings', models.keys);
    controller.set('rootKey', this.rootKey);
    controller.set('session', models.session);
  }
});

App.ServicesRoute = App.BaseRoute.extend({
  model: function(params) {
    var dc = this.modelFor('dc').dc;
    var token = App.get('settings.token');

    // Return a promise to retrieve all of the services
    return Ember.$.getJSON(formatUrl(consulHost + '/v1/internal/ui/services', dc, token)).then(function(data) {
      var objs = [];
      data.map(function(obj){
       objs.push(App.Service.create(obj));
      });
      return objs;
    });
  },
  setupController: function(controller, model) {
    controller.set('services', model);
  }
});

App.ServicesShowRoute = App.BaseRoute.extend({
  model: function(params) {
    var dc = this.modelFor('dc').dc;
    var token = App.get('settings.token');

    // Here we just use the built-in health endpoint, as it gives us everything
    // we need.
    return Ember.$.getJSON(formatUrl(consulHost + '/v1/health/service/' + params.name, dc, token)).then(function(data) {
      var objs = [];
      data.map(function(obj){
       objs.push(App.Node.create(obj));
      });
      return objs;
    });
  },
  setupController: function(controller, model) {
    var tags = [];
    model.map(function(obj){
      if (obj.Service.Tags !== null) {
        tags = tags.concat(obj.Service.Tags);
      }
    });

    tags = tags.filter(function(n){ return n !== undefined; });
    tags = tags.uniq().join(', ');

    controller.set('content', model);
    controller.set('tags', tags);
  }
});

function distance(a, b) {
    a = a.Coord;
    b = b.Coord;
    var sum = 0;
    for (var i = 0; i < a.Vec.length; i++) {
        var diff = a.Vec[i] - b.Vec[i];
        sum += diff * diff;
    }
    var rtt = Math.sqrt(sum) + a.Height + b.Height;

    var adjusted = rtt + a.Adjustment + b.Adjustment;
    if (adjusted > 0.0) {
        rtt = adjusted;
    }

    return Math.round(rtt * 100000.0) / 100.0;
}

App.NodesShowRoute = App.BaseRoute.extend({
  model: function(params) {
    var dc = this.modelFor('dc');
    var token = App.get('settings.token');

    var min = 999999999;
    var max = -999999999;
    var sum = 0;
    var distances = [];
    dc.coordinates.forEach(function (node) {
      if (params.name == node.Node) {
        dc.coordinates.forEach(function (other) {
          if (node.Node != other.Node) {
            var dist = distance(node, other);
            distances.push({ node: other.Node, distance: dist });
            sum += dist;
            if (dist < min) {
              min = dist;
            }
            if (dist > max) {
              max = dist;
            }
          }
        });
        distances.sort(function (a, b) {
          return a.distance - b.distance;
        });
      }
    });
    var n = distances.length;
    var halfN = Math.floor(n / 2);
    var median;

    if (n > 0) {
      if (n % 2) {
        // odd
        median = distances[halfN].distance;
      } else {
        median = (distances[halfN - 1].distance + distances[halfN].distance) / 2;
      }
    } else {
      median = 0;
      min = 0;
      max = 0;
    }

    // Return a promise hash of the node and nodes
    return Ember.RSVP.hash({
      dc: dc.dc,
      token: token,
      tomography: {
        distances: distances,
        n: distances.length,
        min: parseInt(min * 100) / 100,
        median: parseInt(median * 100) / 100,
        max: parseInt(max * 100) / 100
      },
      node: Ember.$.getJSON(formatUrl(consulHost + '/v1/internal/ui/node/' + params.name, dc.dc, token)).then(function(data) {
        return App.Node.create(data);
      }),
      nodes: Ember.$.getJSON(formatUrl(consulHost + '/v1/internal/ui/node/' + params.name, dc.dc, token)).then(function(data) {
        return App.Node.create(data);
      })
    });
  },

  // Load the sessions for the node
  afterModel: function(models) {
    return Ember.$.getJSON(formatUrl(consulHost + '/v1/session/node/' + models.node.Node, models.dc, models.token)).then(function(data) {
      models.sessions = data;
      return models;
    });
  },

  setupController: function(controller, models) {
      controller.set('content', models.node);
      controller.set('sessions', models.sessions);
      controller.set('tomography', models.tomography);
      //
      // Since we have 2 column layout, we need to also display the
      // list of nodes on the left. Hence setting the attribute
      // {{nodes}} on the controller.
      //
      controller.set('nodes', models.nodes);
  }
});

App.NodesRoute = App.BaseRoute.extend({
  model: function(params) {
    var dc = this.modelFor('dc').dc;
    var token = App.get('settings.token');

    // Return a promise containing the nodes
    return Ember.$.getJSON(formatUrl(consulHost + '/v1/internal/ui/nodes', dc, token)).then(function(data) {
      var objs = [];
      data.map(function(obj){
       objs.push(App.Node.create(obj));
      });
      return objs;
    });
  },
  setupController: function(controller, model) {
    controller.set('nodes', model);
  }
});

App.AclsRoute = App.BaseRoute.extend({
  model: function(params) {
    var dc = this.modelFor('dc').dc;
    var token = App.get('settings.token');
    // Return a promise containing the ACLS
    return Ember.$.getJSON(formatUrl(consulHost + '/v1/acl/list', dc, token)).then(function(data) {
      var objs = [];
      data.map(function(obj){
        if (obj.ID === "anonymous") {
          objs.unshift(App.Acl.create(obj));
        } else {
          objs.push(App.Acl.create(obj));
        }
      });
      return objs;
    });
  },

  actions: {
    error: function(error, transition) {
      // If consul returns 401, ACLs are disabled
      if (error && error.status === 401) {
        this.transitionTo('dc.aclsdisabled');
      // If consul returns 403, they key isn't authorized for that
      // action.
      } else if (error && error.status === 403) {
        this.transitionTo('dc.unauthorized');
      }
      return true;
    }
  },

  setupController: function(controller, model) {
      controller.set('acls', model);
      controller.set('newAcl', App.Acl.create());
  }
});

App.AclsShowRoute = App.BaseRoute.extend({
  model: function(params) {
    var dc = this.modelFor('dc').dc;
    var token = App.get('settings.token');

    // Return a promise hash of the node and nodes
    return Ember.RSVP.hash({
      dc: dc,
      acl: Ember.$.getJSON(formatUrl(consulHost + '/v1/acl/info/'+ params.id, dc, token)).then(function(data) {
        return App.Acl.create(data[0]);
      })
    });
  },

  setupController: function(controller, models) {
      controller.set('content', models.acl);
  }
});

App.SettingsRoute = App.BaseRoute.extend({
  model: function(params) {
    return App.get('settings');
  }
});

// Adds any global parameters we need to set to a url/path
function formatUrl(url, dc, token) {
  if (token == null) {
    token = "";
  }
  if (url.indexOf("?") > 0) {
    // If our url has existing params
    url = url + "&dc=" + dc;
    url = url + "&token=" + token;
  } else {
    // Our url doesn't have params
    url = url + "?dc=" + dc;
    url = url + "&token=" + token;
  }
  return url;
}
<|endoftext|>


<commit_before>import Kyber from '@/partners/kyber/kyber.js';
import Web3 from 'web3';
import ENS from 'ethereum-ens';

const nodeUrl = 'https://api.myetherwallet.com/eth';
const network = 'ETH';
const withNetwork = false;

describe('kyber.js', () => {
  beforeEach(done => {
    setTimeout(() => {
      done();
    }, 500);
  });

  it('should instanciate a new instance', () => {
    const web3 = new Web3(nodeUrl);
    const ens = new ENS(web3.currentProvider);
    const kyber = new Kyber({
      network,
      web3: web3,
      ens: ens
    });
    expect(kyber).toBeInstanceOf(Kyber);
  });

  xit('should return the value in token wei', () => {
    const web3 = new Web3(nodeUrl);
    const ens = new ENS(web3.currentProvider);
    const kyber = new Kyber({
      network,
      web3: web3,
      ens: ens
    });

    const weiValue = kyber.convertToTokenBase('GTO', 100000);
    expect(weiValue).toBe('1');
  });

  xit('should return gas limits array from api', async done => {
    const gasLimitList = await kyberCalls.getGasLimits('ETH');
    expect(gasLimitList.data).toBeInstanceOf(Array);
    done();
  });

    const baseValue = kyber.convertToTokenWei('GTO', 1);
    expect(baseValue).toBe('100000');
  });

  xit('should return data for kyber trade tx', async () => {
    const dataValue = {
      data:
        '0xcb3c28c7000000000000000000000000c5bbae50781be1669306b9e001eff57a2957b09d00000000000000000000000000000000000000000000000000000000000186a00000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef000000000000000000000000decaf9cd2367cdbb726e904cd6397edfcae6068d000000000000000000000000000000000000000000000000001fffffffffffff000000000000000000000000000000000000000000000000054ee7e7894c2000000000000000000000000000decaf9cd2367cdbb726e904cd6397edfcae6068d',
      to: '0x818e6fecd516ecc3849daf6845e3ec868087b755',
      value: 0
    };
    const web3 = new Web3(nodeUrl);
    const ens = new ENS(web3.currentProvider);
    const kyber = new Kyber({
      network,
      web3: web3,
      ens: ens
    });

    const baseValue = kyber.convertToTokenWei('GTO', 1);
    const minRate = kyber.convertToTokenWei('BAT', 0.382498);
    const tradeData = await kyber.getTradeData(
      'GTO',
      'BAT',
      baseValue,
      minRate,
      '0xDECAF9CD2367cdbb726E904cD6397eDFcAe6068D'
    );
    expect(tradeData).toMatchObject(dataValue);
  });

  xit('should return data for kyber approval tx', async () => {
    const dataValue = {
      data:
        '0x095ea7b3000000000000000000000000818e6fecd516ecc3849daf6845e3ec868087b75500000000000000000000000000000000000000000000000000000000000186a0',
      to: '0xC5bBaE50781Be1669306b9e001EFF57a2957b09d',
      value: 0
    };

    const web3 = new Web3(nodeUrl);
    const ens = new ENS(web3.currentProvider);
    const kyber = new Kyber({
      network,
      web3: web3,
      ens: ens
    });
    const baseValue = kyber.convertToTokenWei('GTO', 1);
    const approveData = await kyber.approveKyber('GTO', baseValue);
    expect(approveData).toMatchObject(dataValue);
  });

  if (withNetwork) {
    // requires network to function
    it('should retrieve rate for pair in token wei', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });
      const dataForTxs = await kyber.getExpectedRate('ETH', 'BAT', 9);
      expect(dataForTxs).toEqual(expect.anything());
    });

    // requires network to function
    it('should retrieve rate for pair ETH/BAT in tokens', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });
      const baseValue = await kyber.getExpactedRateInTokens('ETH', 'BAT', 9);
      expect(baseValue).toEqual(expect.anything());
    });

    // requires network to function
    it('should retrieve rate for pair BAT/ETH in tokens', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });

      const baseValue = await kyber.getExpactedRateInTokens('BAT', 'ETH', 9);
      expect(baseValue).toEqual(expect.anything());
    });

    // check other pairs (start)
    // requires network to function
    it('should retrieve rate for pair ADX/KNC in tokens', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });
      const baseValue = await kyber.getExpactedRateInTokens('ADX', 'KNC', 9);
      expect(baseValue).toEqual(expect.anything());
    });

    // requires network to function
    it('should retrieve rate for pair BAT/MANA in tokens', async () => {
      // expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });
      const baseValue = await kyber.getExpactedRateInTokens('BAT', 'MANA', 9);
      expect(baseValue).toEqual(expect.anything());
    });
    // check other pairs end

    // requires network to function
    it('should get users kyber network user cap value', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });
      const userCap = await kyber.getUserCapInWei(
        '0x69d4a85BA93C96d007Ee138D5DB3cfeB6AbF4e78'
      );
      expect(userCap).toBe('992063492063492000000');
    });

    // requires network to function
    it('should check if trade does not exceed 95% of users kyber network user cap value', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });

      const result = await kyber.checkUserCap(
        92,
        '0x69d4a85BA93C96d007Ee138D5DB3cfeB6AbF4e78'
      );
      expect(result).toBe(true);
    });

    // requires network to function
    it('should check if trade does exceed 95% of users kyber network user cap value', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });

      const result = await kyber.checkUserCap(
        92063492000000,
        '0x69d4a85BA93C96d007Ee138D5DB3cfeB6AbF4e78'
      );
      expect(result).toBe(false);
    });

    // requires network to function
    it('should check if user has enough tokes allocated to kyber network', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });

      const result = await kyber.allowance(
        'GTO',
        '0x69d4a85BA93C96d007Ee138D5DB3cfeB6AbF4e78'
      );
      expect(result).toBe('0');
    });

    // requires network to function
    it('should check if user has enough tokes allocated to kyber network', async () => {
      expect.assertions(2);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });

      const result = await kyber.isTokenApprovalNeeded(
        'GTO',
        'BAT',
        1000,
        '0x69d4a85BA93C96d007Ee138D5DB3cfeB6AbF4e78'
      );
      expect(result.approve).toBe(true);
      expect(result.reset).toBe(false);
    });

    // requires network to function
    it('should throw error if fromValue exceeds user token balance', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });

      try {
        await kyber.canUserSwap(
          'GTO',
          'BAT',
          1,
          0.382958,
          '0x69d4a85BA93C96d007Ee138D5DB3cfeB6AbF4e78'
        );
      } catch (e) {
        expect(e.message).toMatch(/current token balance/);
      }
    });

    // requires network to function
    it('should throw error if fromValue is in ETH and above user cap', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });

      try {
        await kyber.canUserSwap(
          'ETH',
          'BAT',
          92063492000000,
          116810651600000000,
          '0x69d4a85BA93C96d007Ee138D5DB3cfeB6AbF4e78'
        );
      } catch (e) {
        expect(e.message).toMatch(/user cap value/);
      }
    });

    // requires network to function
    it('should throw error if toValue is in ETH and above user cap', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });

      // 1 BAT
      // 0.000778 ETH
      try {
        await kyber.canUserSwap(
          'BAT',
          'ETH',
          7162539678000,
          9206349200000000,
          '0x69d4a85BA93C96d007Ee138D5DB3cfeB6AbF4e78'
        );
      } catch (e) {
        expect(e.message).toMatch(/user cap value/);
      }
    });

    // requires network to function
    it('should throw an error if a swap is not allowed for the user or supplied details', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });

      try {
        await kyber.generateDataForTransactions(
          'ETH',
          'BAT',
          92063492,
          35256450.769336,
          0.382958,
          '0x69d4a85BA93C96d007Ee138D5DB3cfeB6AbF4e78'
        );
      } catch (e) {
        expect(e.message).toMatch(/user cap value/);
      }
    });

    // requires network to function
    it('should generate data for each transaction needed to perform a swap', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });

      const dataForTxs = await kyber.generateDataForTransactions(
        'ETH',
        'BAT',
        9,
        11419.248186,
        0.382958,
        '0xDECAF9CD2367cdbb726E904cD6397eDFcAe6068D'
      );
      expect(dataForTxs).toEqual(expect.anything());
    });
  }

  // generateDataForTransactions
});
<commit_msg>Fix test<commit_after>import Kyber from '@/partners/kyber/kyber.js';
import Web3 from 'web3';
import ENS from 'ethereum-ens';

const nodeUrl = 'https://api.myetherwallet.com/eth';
const network = 'ETH';
const withNetwork = false;

describe('kyber.js', () => {
  beforeEach(done => {
    setTimeout(() => {
      done();
    }, 500);
  });

  it('should instanciate a new instance', () => {
    const web3 = new Web3(nodeUrl);
    const ens = new ENS(web3.currentProvider);
    const kyber = new Kyber({
      network,
      web3: web3,
      ens: ens
    });
    expect(kyber).toBeInstanceOf(Kyber);
  });

  xit('should return the value in token wei', () => {
    const web3 = new Web3(nodeUrl);
    const ens = new ENS(web3.currentProvider);
    const kyber = new Kyber({
      network,
      web3: web3,
      ens: ens
    });

    const weiValue = kyber.convertToTokenBase('GTO', 100000);
    expect(weiValue).toBe('1');
  });

  xit('should return gas limits array from api', async done => {
    // const gasLimitList = await kyberCalls.getGasLimits('ETH');
    // expect(gasLimitList.data).toBeInstanceOf(Array);
    done();
  });

  xit('should return data for kyber trade tx', async () => {
    const dataValue = {
      data:
        '0xcb3c28c7000000000000000000000000c5bbae50781be1669306b9e001eff57a2957b09d00000000000000000000000000000000000000000000000000000000000186a00000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef000000000000000000000000decaf9cd2367cdbb726e904cd6397edfcae6068d000000000000000000000000000000000000000000000000001fffffffffffff000000000000000000000000000000000000000000000000054ee7e7894c2000000000000000000000000000decaf9cd2367cdbb726e904cd6397edfcae6068d',
      to: '0x818e6fecd516ecc3849daf6845e3ec868087b755',
      value: 0
    };
    const web3 = new Web3(nodeUrl);
    const ens = new ENS(web3.currentProvider);
    const kyber = new Kyber({
      network,
      web3: web3,
      ens: ens
    });

    const baseValue = kyber.convertToTokenWei('GTO', 1);
    const minRate = kyber.convertToTokenWei('BAT', 0.382498);
    const tradeData = await kyber.getTradeData(
      'GTO',
      'BAT',
      baseValue,
      minRate,
      '0xDECAF9CD2367cdbb726E904cD6397eDFcAe6068D'
    );
    expect(tradeData).toMatchObject(dataValue);
  });

  xit('should return data for kyber approval tx', async () => {
    const dataValue = {
      data:
        '0x095ea7b3000000000000000000000000818e6fecd516ecc3849daf6845e3ec868087b75500000000000000000000000000000000000000000000000000000000000186a0',
      to: '0xC5bBaE50781Be1669306b9e001EFF57a2957b09d',
      value: 0
    };

    const web3 = new Web3(nodeUrl);
    const ens = new ENS(web3.currentProvider);
    const kyber = new Kyber({
      network,
      web3: web3,
      ens: ens
    });
    const baseValue = kyber.convertToTokenWei('GTO', 1);
    const approveData = await kyber.approveKyber('GTO', baseValue);
    expect(approveData).toMatchObject(dataValue);
  });

  if (withNetwork) {
    // requires network to function
    it('should retrieve rate for pair in token wei', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });
      const dataForTxs = await kyber.getExpectedRate('ETH', 'BAT', 9);
      expect(dataForTxs).toEqual(expect.anything());
    });

    // requires network to function
    it('should retrieve rate for pair ETH/BAT in tokens', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });
      const baseValue = await kyber.getExpactedRateInTokens('ETH', 'BAT', 9);
      expect(baseValue).toEqual(expect.anything());
    });

    // requires network to function
    it('should retrieve rate for pair BAT/ETH in tokens', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });

      const baseValue = await kyber.getExpactedRateInTokens('BAT', 'ETH', 9);
      expect(baseValue).toEqual(expect.anything());
    });

    // check other pairs (start)
    // requires network to function
    it('should retrieve rate for pair ADX/KNC in tokens', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });
      const baseValue = await kyber.getExpactedRateInTokens('ADX', 'KNC', 9);
      expect(baseValue).toEqual(expect.anything());
    });

    // requires network to function
    it('should retrieve rate for pair BAT/MANA in tokens', async () => {
      // expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });
      const baseValue = await kyber.getExpactedRateInTokens('BAT', 'MANA', 9);
      expect(baseValue).toEqual(expect.anything());
    });
    // check other pairs end

    // requires network to function
    it('should get users kyber network user cap value', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });
      const userCap = await kyber.getUserCapInWei(
        '0x69d4a85BA93C96d007Ee138D5DB3cfeB6AbF4e78'
      );
      expect(userCap).toBe('992063492063492000000');
    });

    // requires network to function
    it('should check if trade does not exceed 95% of users kyber network user cap value', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });

      const result = await kyber.checkUserCap(
        92,
        '0x69d4a85BA93C96d007Ee138D5DB3cfeB6AbF4e78'
      );
      expect(result).toBe(true);
    });

    // requires network to function
    it('should check if trade does exceed 95% of users kyber network user cap value', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });

      const result = await kyber.checkUserCap(
        92063492000000,
        '0x69d4a85BA93C96d007Ee138D5DB3cfeB6AbF4e78'
      );
      expect(result).toBe(false);
    });

    // requires network to function
    it('should check if user has enough tokes allocated to kyber network', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });

      const result = await kyber.allowance(
        'GTO',
        '0x69d4a85BA93C96d007Ee138D5DB3cfeB6AbF4e78'
      );
      expect(result).toBe('0');
    });

    // requires network to function
    it('should check if user has enough tokes allocated to kyber network', async () => {
      expect.assertions(2);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });

      const result = await kyber.isTokenApprovalNeeded(
        'GTO',
        'BAT',
        1000,
        '0x69d4a85BA93C96d007Ee138D5DB3cfeB6AbF4e78'
      );
      expect(result.approve).toBe(true);
      expect(result.reset).toBe(false);
    });

    // requires network to function
    it('should throw error if fromValue exceeds user token balance', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });

      try {
        await kyber.canUserSwap(
          'GTO',
          'BAT',
          1,
          0.382958,
          '0x69d4a85BA93C96d007Ee138D5DB3cfeB6AbF4e78'
        );
      } catch (e) {
        expect(e.message).toMatch(/current token balance/);
      }
    });

    // requires network to function
    it('should throw error if fromValue is in ETH and above user cap', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });

      try {
        await kyber.canUserSwap(
          'ETH',
          'BAT',
          92063492000000,
          116810651600000000,
          '0x69d4a85BA93C96d007Ee138D5DB3cfeB6AbF4e78'
        );
      } catch (e) {
        expect(e.message).toMatch(/user cap value/);
      }
    });

    // requires network to function
    it('should throw error if toValue is in ETH and above user cap', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });

      // 1 BAT
      // 0.000778 ETH
      try {
        await kyber.canUserSwap(
          'BAT',
          'ETH',
          7162539678000,
          9206349200000000,
          '0x69d4a85BA93C96d007Ee138D5DB3cfeB6AbF4e78'
        );
      } catch (e) {
        expect(e.message).toMatch(/user cap value/);
      }
    });

    // requires network to function
    it('should throw an error if a swap is not allowed for the user or supplied details', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });

      try {
        await kyber.generateDataForTransactions(
          'ETH',
          'BAT',
          92063492,
          35256450.769336,
          0.382958,
          '0x69d4a85BA93C96d007Ee138D5DB3cfeB6AbF4e78'
        );
      } catch (e) {
        expect(e.message).toMatch(/user cap value/);
      }
    });

    // requires network to function
    it('should generate data for each transaction needed to perform a swap', async () => {
      expect.assertions(1);
      const web3 = new Web3(nodeUrl);
      const ens = new ENS(web3.currentProvider);
      const kyber = new Kyber({
        network,
        web3: web3,
        ens: ens
      });

      const dataForTxs = await kyber.generateDataForTransactions(
        'ETH',
        'BAT',
        9,
        11419.248186,
        0.382958,
        '0xDECAF9CD2367cdbb726E904cD6397eDFcAe6068D'
      );
      expect(dataForTxs).toEqual(expect.anything());
    });
  }

  // generateDataForTransactions
});
<|endoftext|>


<commit_before>'use strict';

var expect            = require('chai').expect;
var LiveReloadServer  = require('../../../../lib/tasks/server/livereload-server');
var MockUI            = require('../../../helpers/mock-ui');
var MockExpressServer = require('../../../helpers/mock-express-server');
var net               = require('net');
var EOL               = require('os').EOL;
var path              = require('path');
var MockWatcher       = require('../../../helpers/mock-watcher');
var FSTree            = require('fs-tree-diff');

describe('livereload-server', function() {
  var subject;
  var ui;
  var watcher;
  var expressServer;

  beforeEach(function() {
    ui = new MockUI();
    watcher = new MockWatcher();
    expressServer = new MockExpressServer();

    subject = new LiveReloadServer({
      ui: ui,
      watcher: watcher,
      expressServer: expressServer,
      analytics: { trackError: function() { } },
      project: {
        liveReloadFilterPatterns: [],
        root: '/home/user/my-project'
      }
    });
  });

  afterEach(function() {
    try {
      if (subject._liveReloadServer) {
        subject._liveReloadServer.close();
      }
    } catch (err) { }
  });

  describe('start', function() {
    it('does not start the server if `liveReload` option is not true', function() {
      return subject.start({
        liveReloadPort: 1337,
        liveReload: false
      }).then(function(output) {
        expect(output).to.equal('Livereload server manually disabled.');
        expect(!!subject._liveReloadServer).to.equal(false);
      });
    });

    it('correctly indicates which port livereload is present on', function() {
      return subject.start({
        liveReloadPort: 1337,
        liveReloadHost: 'localhost',
        liveReload: true
      }).then(function() {
        expect(ui.output).to.equal('Livereload server on http://localhost:1337' + EOL);
      });
    });

    it('informs of error during startup', function(done) {
      var preexistingServer = net.createServer();
      preexistingServer.listen(1337);

      return subject.start({
          liveReloadPort: 1337,
          liveReload: true
        })
        .catch(function(reason) {
          expect(reason).to.equal('Livereload failed on http://localhost:1337.  It is either in use or you do not have permission.' + EOL);
        })
        .finally(function() {
          preexistingServer.close(done);
        });
    });

    it('starts with custom host', function() {
      return subject.start({
        liveReloadHost: '127.0.0.1',
        liveReloadPort: 1337,
        liveReload: true
      }).then(function() {
        expect(ui.output).to.equal('Livereload server on http://127.0.0.1:1337' + EOL);
      });
    });
  });

  describe('start with https', function() {
    it('correctly indicates which port livereload is present on and running in https mode', function() {
      return subject.start({
        liveReloadPort: 1337,
        liveReloadHost: 'localhost',
        liveReload: true,
        ssl: true,
        sslKey: 'tests/fixtures/ssl/server.key',
        sslCert: 'tests/fixtures/ssl/server.crt'
      }).then(function() {
        expect(ui.output).to.equal('Livereload server on https://localhost:1337' + EOL);
      });
    });

    it('informs of error during startup', function(done) {
      var preexistingServer = net.createServer();
      preexistingServer.listen(1337);

      return subject.start({
          liveReloadPort: 1337,
          liveReload: true,
          ssl: true,
          sslKey: 'tests/fixtures/ssl/server.key',
          sslCert: 'tests/fixtures/ssl/server.crt'
        })
        .catch(function(reason) {
          expect(reason).to.equal('Livereload failed on https://localhost:1337.  It is either in use or you do not have permission.' + EOL);
        })
        .finally(function() {
          preexistingServer.close(done);
        });
    });
  });

  describe('express server restart', function() {
    it('triggers when the express server restarts', function() {
      var calls = 0;
      subject.didRestart = function () {
        calls++;
      };

      return subject.start({
          liveReloadPort: 1337,
          liveReload: true
        }).then(function () {
          expressServer.emit('restart');
          expect(calls).to.equal(1);
        });
    });
  });

  describe('livereload changes', function () {
    var liveReloadServer;
    var changedCount;
    var oldChanged;
    var stubbedChanged = function() {
      changedCount += 1;
    };
    var trackCount;
    var oldTrack;
    var stubbedTrack = function() {
      trackCount += 1;
    };
    var createStubbedGetDirectoryEntries = function(files) {
      return function() {
        return files.map(function(file) {
          return {
            relativePath: file,
            isDirectory: function() {
              return false;
            }
          };
        });
      };
    };

    beforeEach(function() {
      liveReloadServer = subject.liveReloadServer();
      changedCount = 0;
      oldChanged = liveReloadServer.changed;
      liveReloadServer.changed = stubbedChanged;

      trackCount = 0;
      oldTrack = subject.analytics.track;
      subject.analytics.track = stubbedTrack;

      subject.tree = new FSTree.fromEntries([]);
    });

    afterEach(function() {
      liveReloadServer.changed = oldChanged;
      subject.analytics.track = oldTrack;
      subject.project.liveReloadFilterPatterns = [];
    });

    describe('watcher events', function () {
      function watcherEventTest(eventName, expectedCount) {
        subject.getDirectoryEntries = createStubbedGetDirectoryEntries([
          'test/fixtures/proxy/file-a.js'
        ]);
        subject.project.liveReloadFilterPatterns = [];
        return subject.start({
          liveReloadPort: 1337,
          liveReload: true
        }).then(function () {
            watcher.emit(eventName, {
              directory: '/home/user/projects/my-project/tmp/something.tmp'
            });
          }).finally(function () {
            expect(changedCount).to.equal(expectedCount);
          });
      }

      it('triggers a livereload change on a watcher change event', function () {
        return watcherEventTest('change', 1);
      });

      it('triggers a livereload change on a watcher error event', function () {
        return watcherEventTest('error', 1);
      });

      it('does not trigger a livereload change on other watcher events', function () {
        return watcherEventTest('not-an-event', 0);
      });

      describe('filter pattern', function() {
        it('shouldTriggerReload must be true if there are no liveReloadFilterPatterns', function() {
          subject.project.liveReloadFilterPatterns = [];
          var result = subject.shouldTriggerReload({
            filePath: '/home/user/my-project/app/styles/app.css'
          });
          expect(result).to.be.true;
        });

        it('shouldTriggerReload is true when no liveReloadFilterPatterns matches the filePath', function() {
          var basePath = path.normalize('test/fixtures/proxy').replace(/\\/g, '\\\\');
          var filter = new RegExp('^' + basePath);

          subject.project.liveReloadFilterPatterns = [filter];
          var result = subject.shouldTriggerReload({
            filePath: '/home/user/my-project/app/styles/app.css'
          });
          expect(result).to.be.true;
        });

        it('shouldTriggerReload is false when one or more of the liveReloadFilterPatterns matches filePath', function() {
          var basePath = path.normalize('test/fixtures/proxy').replace(/\\/g, '\\\\');
          var filter = new RegExp('^' + basePath);

          subject.project.liveReloadFilterPatterns = [filter];
          var result = subject.shouldTriggerReload({
            filePath: '/home/user/my-project/test/fixtures/proxy/file-a.js'
          });
          expect(result).to.be.false;
        });

        it('shouldTriggerReload writes a banner after skipping reload for a file', function() {
          var basePath = path.normalize('test/fixtures/proxy').replace(/\\/g, '\\\\');
          var filter = new RegExp('^' + basePath);

          subject.project.liveReloadFilterPatterns = [filter];
          var result = subject.shouldTriggerReload({
            filePath: '/home/user/my-project/test/fixtures/proxy/file-a.js'
          });
          expect(ui.output).to.equal('Skipping livereload for: test/fixtures/proxy/file-a.js' + EOL);
        });

        it('triggers the livereload server of a change when no pattern matches', function() {
          subject.getDirectoryEntries = createStubbedGetDirectoryEntries([]);
          subject.didChange({
            filePath: '/home/user/my-project/test/fixtures/proxy/file-a.js'
          });
          expect(changedCount).to.equal(1);
          expect(trackCount).to.equal(1);
        });

        it('does not trigger livereload server of a change when there is a pattern match', function() {
          // normalize test regex for windows
          // path.normalize with change forward slashes to back slashes if test is running on windows
          // we then replace backslashes with double backslahes to escape the backslash in the regex
          var basePath = path.normalize('test/fixtures/proxy').replace(/\\/g, '\\\\');
          var filter = new RegExp('^' + basePath);

          subject.project.liveReloadFilterPatterns = [filter];

          subject.getDirectoryEntries = createStubbedGetDirectoryEntries([]);
          subject.didChange({
            filePath: '/home/user/my-project/test/fixtures/proxy/file-a.js'
          });

          expect(changedCount).to.equal(0);
          expect(trackCount).to.equal(0);
        });
      });
    });

    describe('specific files', function() {
      var reloadedFiles;

      var stubbedChanged = function(options) {
        reloadedFiles = options.body.files;
      };

      beforeEach(function() {
        liveReloadServer.changed = stubbedChanged;
      });

      afterEach(function() {
        reloadedFiles = undefined;
      });

      it('triggers livereload with modified files', function() {
        var changedFiles = [
          'assets/my-project.css',
          'assets/my-project.js'
        ];

        subject.getDirectoryEntries = createStubbedGetDirectoryEntries(changedFiles);
        subject.didChange({
          directory: '/home/user/projects/my-project/tmp/something.tmp'
        });

        expect(reloadedFiles).to.deep.equal(changedFiles);
      });

      it('triggers livereload ignoring source map files', function() {
        var changedFiles = [
          'assets/my-project.css',
          'assets/my-project.css.map'
        ];

        var expectedResult = [
          'assets/my-project.css'
        ];

        subject.getDirectoryEntries = createStubbedGetDirectoryEntries(changedFiles);
        subject.didChange({
          directory: '/home/user/projects/my-project/tmp/something.tmp'
        });

        expect(reloadedFiles).to.deep.equal(expectedResult);
      });
    });
  });
});
<commit_msg>Removes unsed var in tests<commit_after>'use strict';

var expect            = require('chai').expect;
var LiveReloadServer  = require('../../../../lib/tasks/server/livereload-server');
var MockUI            = require('../../../helpers/mock-ui');
var MockExpressServer = require('../../../helpers/mock-express-server');
var net               = require('net');
var EOL               = require('os').EOL;
var path              = require('path');
var MockWatcher       = require('../../../helpers/mock-watcher');
var FSTree            = require('fs-tree-diff');

describe('livereload-server', function() {
  var subject;
  var ui;
  var watcher;
  var expressServer;

  beforeEach(function() {
    ui = new MockUI();
    watcher = new MockWatcher();
    expressServer = new MockExpressServer();

    subject = new LiveReloadServer({
      ui: ui,
      watcher: watcher,
      expressServer: expressServer,
      analytics: { trackError: function() { } },
      project: {
        liveReloadFilterPatterns: [],
        root: '/home/user/my-project'
      }
    });
  });

  afterEach(function() {
    try {
      if (subject._liveReloadServer) {
        subject._liveReloadServer.close();
      }
    } catch (err) { }
  });

  describe('start', function() {
    it('does not start the server if `liveReload` option is not true', function() {
      return subject.start({
        liveReloadPort: 1337,
        liveReload: false
      }).then(function(output) {
        expect(output).to.equal('Livereload server manually disabled.');
        expect(!!subject._liveReloadServer).to.equal(false);
      });
    });

    it('correctly indicates which port livereload is present on', function() {
      return subject.start({
        liveReloadPort: 1337,
        liveReloadHost: 'localhost',
        liveReload: true
      }).then(function() {
        expect(ui.output).to.equal('Livereload server on http://localhost:1337' + EOL);
      });
    });

    it('informs of error during startup', function(done) {
      var preexistingServer = net.createServer();
      preexistingServer.listen(1337);

      return subject.start({
          liveReloadPort: 1337,
          liveReload: true
        })
        .catch(function(reason) {
          expect(reason).to.equal('Livereload failed on http://localhost:1337.  It is either in use or you do not have permission.' + EOL);
        })
        .finally(function() {
          preexistingServer.close(done);
        });
    });

    it('starts with custom host', function() {
      return subject.start({
        liveReloadHost: '127.0.0.1',
        liveReloadPort: 1337,
        liveReload: true
      }).then(function() {
        expect(ui.output).to.equal('Livereload server on http://127.0.0.1:1337' + EOL);
      });
    });
  });

  describe('start with https', function() {
    it('correctly indicates which port livereload is present on and running in https mode', function() {
      return subject.start({
        liveReloadPort: 1337,
        liveReloadHost: 'localhost',
        liveReload: true,
        ssl: true,
        sslKey: 'tests/fixtures/ssl/server.key',
        sslCert: 'tests/fixtures/ssl/server.crt'
      }).then(function() {
        expect(ui.output).to.equal('Livereload server on https://localhost:1337' + EOL);
      });
    });

    it('informs of error during startup', function(done) {
      var preexistingServer = net.createServer();
      preexistingServer.listen(1337);

      return subject.start({
          liveReloadPort: 1337,
          liveReload: true,
          ssl: true,
          sslKey: 'tests/fixtures/ssl/server.key',
          sslCert: 'tests/fixtures/ssl/server.crt'
        })
        .catch(function(reason) {
          expect(reason).to.equal('Livereload failed on https://localhost:1337.  It is either in use or you do not have permission.' + EOL);
        })
        .finally(function() {
          preexistingServer.close(done);
        });
    });
  });

  describe('express server restart', function() {
    it('triggers when the express server restarts', function() {
      var calls = 0;
      subject.didRestart = function () {
        calls++;
      };

      return subject.start({
          liveReloadPort: 1337,
          liveReload: true
        }).then(function () {
          expressServer.emit('restart');
          expect(calls).to.equal(1);
        });
    });
  });

  describe('livereload changes', function () {
    var liveReloadServer;
    var changedCount;
    var oldChanged;
    var stubbedChanged = function() {
      changedCount += 1;
    };
    var trackCount;
    var oldTrack;
    var stubbedTrack = function() {
      trackCount += 1;
    };
    var createStubbedGetDirectoryEntries = function(files) {
      return function() {
        return files.map(function(file) {
          return {
            relativePath: file,
            isDirectory: function() {
              return false;
            }
          };
        });
      };
    };

    beforeEach(function() {
      liveReloadServer = subject.liveReloadServer();
      changedCount = 0;
      oldChanged = liveReloadServer.changed;
      liveReloadServer.changed = stubbedChanged;

      trackCount = 0;
      oldTrack = subject.analytics.track;
      subject.analytics.track = stubbedTrack;

      subject.tree = new FSTree.fromEntries([]);
    });

    afterEach(function() {
      liveReloadServer.changed = oldChanged;
      subject.analytics.track = oldTrack;
      subject.project.liveReloadFilterPatterns = [];
    });

    describe('watcher events', function () {
      function watcherEventTest(eventName, expectedCount) {
        subject.getDirectoryEntries = createStubbedGetDirectoryEntries([
          'test/fixtures/proxy/file-a.js'
        ]);
        subject.project.liveReloadFilterPatterns = [];
        return subject.start({
          liveReloadPort: 1337,
          liveReload: true
        }).then(function () {
            watcher.emit(eventName, {
              directory: '/home/user/projects/my-project/tmp/something.tmp'
            });
          }).finally(function () {
            expect(changedCount).to.equal(expectedCount);
          });
      }

      it('triggers a livereload change on a watcher change event', function () {
        return watcherEventTest('change', 1);
      });

      it('triggers a livereload change on a watcher error event', function () {
        return watcherEventTest('error', 1);
      });

      it('does not trigger a livereload change on other watcher events', function () {
        return watcherEventTest('not-an-event', 0);
      });

      describe('filter pattern', function() {
        it('shouldTriggerReload must be true if there are no liveReloadFilterPatterns', function() {
          subject.project.liveReloadFilterPatterns = [];
          var result = subject.shouldTriggerReload({
            filePath: '/home/user/my-project/app/styles/app.css'
          });
          expect(result).to.be.true;
        });

        it('shouldTriggerReload is true when no liveReloadFilterPatterns matches the filePath', function() {
          var basePath = path.normalize('test/fixtures/proxy').replace(/\\/g, '\\\\');
          var filter = new RegExp('^' + basePath);

          subject.project.liveReloadFilterPatterns = [filter];
          var result = subject.shouldTriggerReload({
            filePath: '/home/user/my-project/app/styles/app.css'
          });
          expect(result).to.be.true;
        });

        it('shouldTriggerReload is false when one or more of the liveReloadFilterPatterns matches filePath', function() {
          var basePath = path.normalize('test/fixtures/proxy').replace(/\\/g, '\\\\');
          var filter = new RegExp('^' + basePath);

          subject.project.liveReloadFilterPatterns = [filter];
          var result = subject.shouldTriggerReload({
            filePath: '/home/user/my-project/test/fixtures/proxy/file-a.js'
          });
          expect(result).to.be.false;
        });

        it('shouldTriggerReload writes a banner after skipping reload for a file', function() {
          var basePath = path.normalize('test/fixtures/proxy').replace(/\\/g, '\\\\');
          var filter = new RegExp('^' + basePath);

          subject.project.liveReloadFilterPatterns = [filter];
          subject.shouldTriggerReload({
            filePath: '/home/user/my-project/test/fixtures/proxy/file-a.js'
          });
          expect(ui.output).to.equal('Skipping livereload for: test/fixtures/proxy/file-a.js' + EOL);
        });

        it('triggers the livereload server of a change when no pattern matches', function() {
          subject.getDirectoryEntries = createStubbedGetDirectoryEntries([]);
          subject.didChange({
            filePath: '/home/user/my-project/test/fixtures/proxy/file-a.js'
          });
          expect(changedCount).to.equal(1);
          expect(trackCount).to.equal(1);
        });

        it('does not trigger livereload server of a change when there is a pattern match', function() {
          // normalize test regex for windows
          // path.normalize with change forward slashes to back slashes if test is running on windows
          // we then replace backslashes with double backslahes to escape the backslash in the regex
          var basePath = path.normalize('test/fixtures/proxy').replace(/\\/g, '\\\\');
          var filter = new RegExp('^' + basePath);

          subject.project.liveReloadFilterPatterns = [filter];

          subject.getDirectoryEntries = createStubbedGetDirectoryEntries([]);
          subject.didChange({
            filePath: '/home/user/my-project/test/fixtures/proxy/file-a.js'
          });

          expect(changedCount).to.equal(0);
          expect(trackCount).to.equal(0);
        });
      });
    });

    describe('specific files', function() {
      var reloadedFiles;

      var stubbedChanged = function(options) {
        reloadedFiles = options.body.files;
      };

      beforeEach(function() {
        liveReloadServer.changed = stubbedChanged;
      });

      afterEach(function() {
        reloadedFiles = undefined;
      });

      it('triggers livereload with modified files', function() {
        var changedFiles = [
          'assets/my-project.css',
          'assets/my-project.js'
        ];

        subject.getDirectoryEntries = createStubbedGetDirectoryEntries(changedFiles);
        subject.didChange({
          directory: '/home/user/projects/my-project/tmp/something.tmp'
        });

        expect(reloadedFiles).to.deep.equal(changedFiles);
      });

      it('triggers livereload ignoring source map files', function() {
        var changedFiles = [
          'assets/my-project.css',
          'assets/my-project.css.map'
        ];

        var expectedResult = [
          'assets/my-project.css'
        ];

        subject.getDirectoryEntries = createStubbedGetDirectoryEntries(changedFiles);
        subject.didChange({
          directory: '/home/user/projects/my-project/tmp/something.tmp'
        });

        expect(reloadedFiles).to.deep.equal(expectedResult);
      });
    });
  });
});
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react';
import ReactDOM from 'react-dom';

//const HEIGHT = 91.14378277661477;
//const WIDTH = 91.14378277661477;
//const SIDE = 50.0;
const HEIGHT = 51.96152422706631;
const WIDTH = 51.96152422706631;
const SIDE = 30.0;

function pad(num) {
  let s = num + '';
  if (s.length === 1) {
    s = '0' + num;
  }
  return s;
}

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}

class Hexagon {
  constructor(row, col, x, y) {
    const x1 = (WIDTH - SIDE) / 2;
    const y1 = HEIGHT / 2;

    this.points = [
      new Point(x1 + x, y),
      new Point(x1 + SIDE + x, y),
      new Point(x + WIDTH, y1 + y),
      new Point(x1 + SIDE + x, HEIGHT + y),
      new Point(x1 + x, HEIGHT + y),
      new Point(x, y1 + y),
    ];

    let firstDigit = col + 1;
    let secondDigit = row;

    if (col % 2 === 0) {
      secondDigit = (row / 2) + 1;
    } else {
      secondDigit = ((row - (row % 2)) / 2) + 1;
    }

    this.id = pad(firstDigit) + pad(secondDigit);

    this.x = x;
    this.y = y;
    this.x1 = x1;
    this.y1 = y1;

    this.topLeft = new Point(this.x, this.y);
    this.bottomRight = new Point(this.x + WIDTH, this.y + HEIGHT);
    this.middle = new Point(this.x + (WIDTH / 2), this.y + (HEIGHT / 2));
  }

  draw(ctx) {
    ctx.strokeStyle = 'grey';
    ctx.lineWidth = 1;
    ctx.beginPath();
    ctx.moveTo(this.points[0].x, this.points[0].y);
    for (let i = 1; i < this.points.length; i++) {
      const point = this.points[i];
      ctx.lineTo(point.x, point.y);
    }
    ctx.closePath();
    ctx.stroke();
    // add text. Right now just coordinates
    ctx.fillStyle = 'black';
    ctx.font = 'bolder 6pt Trebuchet MS,Tahoma,Verdana,Arial,sans-serif';
    ctx.textAlign = 'center';
    ctx.textBaseLine = 'middle';
    ctx.fillText(this.id, this.middle.x, this.middle.y - 10);
  }
}

class Grid {
  // this will take a list of worlds at some point
  // from this we can add the specific data
  constructor(width, height) {
    this.hexes = [];
    // fast look up by x/y coords
    this.hexesDict = {};

    let row = 0;
    let y = 0.0;

    while (y + HEIGHT <= height) {
      let col = 0;
      let offset = 0.0;
      if (row % 2 === 1) {
        offset = (WIDTH - SIDE) / 2 + SIDE;
        col = 1;
      }
      let x = offset;
      while (x + WIDTH <= width) {
        const hex = new Hexagon(row, col, x, y);
        this.hexes.push(hex);
        col += 2;
        x += WIDTH + SIDE;
      }
      row++;
      y += HEIGHT / 2;
    }
  }
  draw(ctx) {
    ctx.clearRect(0, 0, 800, 800);
    this.hexes.forEach(hex => hex.draw(ctx));
  }
}

class Starmap extends React.Component {

  componentDidMount() {
    this.paint(this.getDOMNode().getContext('2d'));
  }

  componentDidUpdate() {
    const ctx = this.getDOMNode().getContext('2d');
    this.paint(ctx);
  }

  getDOMNode() {
    return ReactDOM.findDOMNode(this);
  }

  paint(ctx) {
    this.grid = new Grid(360, 560);
    this.grid.draw(ctx);
  }

  render() {
    return <canvas width={360} height={550} />;
  }

}

Starmap.propTypes = {
};

export default Starmap;
<commit_msg>Got canvas Y/X click<commit_after>import React, { PropTypes } from 'react';
import ReactDOM from 'react-dom';

//const HEIGHT = 91.14378277661477;
//const WIDTH = 91.14378277661477;
//const SIDE = 50.0;
const HEIGHT = 51.96152422706631;
const WIDTH = 51.96152422706631;
const SIDE = 30.0;

function pad(num) {
  let s = num + '';
  if (s.length === 1) {
    s = '0' + num;
  }
  return s;
}

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}

class Hexagon {
  constructor(row, col, x, y) {
    const x1 = (WIDTH - SIDE) / 2;
    const y1 = HEIGHT / 2;

    this.points = [
      new Point(x1 + x, y),
      new Point(x1 + SIDE + x, y),
      new Point(x + WIDTH, y1 + y),
      new Point(x1 + SIDE + x, HEIGHT + y),
      new Point(x1 + x, HEIGHT + y),
      new Point(x, y1 + y),
    ];

    const firstDigit = col + 1;
    let secondDigit = row;

    if (col % 2 === 0) {
      secondDigit = (row / 2) + 1;
    } else {
      secondDigit = ((row - (row % 2)) / 2) + 1;
    }

    this.id = pad(firstDigit) + pad(secondDigit);

    this.x = x;
    this.y = y;
    this.x1 = x1;
    this.y1 = y1;

    this.topLeft = new Point(this.x, this.y);
    this.bottomRight = new Point(this.x + WIDTH, this.y + HEIGHT);
    this.middle = new Point(this.x + (WIDTH / 2), this.y + (HEIGHT / 2));
  }

  contains(x, y) {
    return (this.topLeft.x < x &&
      this.topLeft.y < y &&
      x < this.bottomRight.x &&
      y < this.bottomRight.y);
  }

  draw(ctx) {
    ctx.strokeStyle = 'grey';
    ctx.lineWidth = 1;
    ctx.beginPath();
    ctx.moveTo(this.points[0].x, this.points[0].y);
    for (let i = 1; i < this.points.length; i++) {
      const point = this.points[i];
      ctx.lineTo(point.x, point.y);
    }
    ctx.closePath();
    ctx.stroke();
    // add text. Right now just coordinates
    ctx.fillStyle = 'black';
    ctx.font = 'bolder 6pt Trebuchet MS,Tahoma,Verdana,Arial,sans-serif';
    ctx.textAlign = 'center';
    ctx.textBaseLine = 'middle';
    ctx.fillText(this.id, this.middle.x, this.middle.y - 10);
  }
}

class Grid {
  // this will take a list of worlds at some point
  // from this we can add the specific data
  constructor(width, height) {
    this.hexes = [];
    // fast look up by x/y coords
    this.hexesDict = {};

    let row = 0;
    let y = 0.0;

    while (y + HEIGHT <= height) {
      let col = 0;
      let offset = 0.0;
      if (row % 2 === 1) {
        offset = (WIDTH - SIDE) / 2 + SIDE;
        col = 1;
      }
      let x = offset;
      while (x + WIDTH <= width) {
        const hex = new Hexagon(row, col, x, y);
        this.hexes.push(hex);
        this.hexesDict[hex.id] = hex;
        col += 2;
        x += WIDTH + SIDE;
      }
      row++;
      y += HEIGHT / 2;
    }
  }
  draw(ctx) {
    ctx.clearRect(0, 0, 360, 550);
    this.hexes.forEach(hex => hex.draw(ctx));
  }

  getHexByXY(x, y) {
    for (let i = 0; i < this.hexes.length; i++) {
      const hex = this.hexes[i];
      if (hex.contains(x, y)) {
        return hex;
      }
    }
    return null;
  }
}

class Starmap extends React.Component {

  constructor(props) {
    super(props);
    this.onClick = this.onClick.bind(this);
    this.grid = new Grid(360, 560);
  }

  componentDidMount() {
    this.paint(this.getDOMNode().getContext('2d'));
  }

  componentDidUpdate() {
    const ctx = this.getDOMNode().getContext('2d');
    this.paint(ctx);
  }
  getDOMNode() {
    return ReactDOM.findDOMNode(this);
  }

  onClick(event) {
    let totalOffsetX = 0;
    let totalOffsetY = 0;
    let element = event.currentTarget;

    while (element) {
      totalOffsetX += element.offsetLeft - element.scrollLeft;
      totalOffsetY += element.offsetTop - element.scrollTop;
      element = element.offsetParent;
    }

    const x = event.pageX - totalOffsetX - document.body.scrollLeft;
    const y = event.pageY - totalOffsetY - document.body.scrollTop;

    console.log(this.grid.getHexByXY(x, y));
  }

  paint(ctx) {
    this.grid.draw(ctx);
  }

  render() {
    return <canvas width={360} height={550} onClick={this.onClick} />;
  }

}

Starmap.propTypes = {
};

export default Starmap;
<|endoftext|>


<commit_before>define("ace/theme/dawn",["require","exports","module","ace/lib/dom"], function(require, exports, module) {

exports.isDark = false;
exports.cssClass = "ace-dawn";
exports.cssText = ".ace-dawn .ace_gutter {\
background: #ebebeb;\
color: #333\
}\
.ace-dawn .ace_print-margin {\
width: 1px;\
background: #e8e8e8\
}\
.ace-dawn {\
background-color: #F9F9F9;\
color: #080808\
}\
.ace-dawn .ace_cursor {\
color: #000000\
}\
.ace-dawn .ace_marker-layer .ace_selection {\
background: rgba(39, 95, 255, 0.30)\
}\
.ace-dawn.ace_multiselect .ace_selection.ace_start {\
box-shadow: 0 0 3px 0px #F9F9F9;\
}\
.ace-dawn .ace_marker-layer .ace_step {\
background: rgb(255, 255, 0)\
}\
.ace-dawn .ace_marker-layer .ace_bracket {\
margin: -1px 0 0 -1px;\
border: 1px solid rgba(75, 75, 126, 0.50)\
}\
.ace-dawn .ace_marker-layer .ace_active-line {\
background: rgba(36, 99, 180, 0.12)\
}\
.ace-dawn .ace_gutter-active-line {\
background-color : #dcdcdc\
}\
.ace-dawn .ace_marker-layer .ace_selected-word {\
border: 1px solid rgba(39, 95, 255, 0.30)\
}\
.ace-dawn .ace_invisible {\
color: rgba(75, 75, 126, 0.50)\
}\
.ace-dawn .ace_keyword,\
.ace-dawn .ace_meta {\
color: #794938\
}\
.ace-dawn .ace_constant,\
.ace-dawn .ace_constant.ace_character,\
.ace-dawn .ace_constant.ace_character.ace_escape,\
.ace-dawn .ace_constant.ace_other {\
color: #811F24\
}\
.ace-dawn .ace_invalid.ace_illegal {\
text-decoration: underline;\
font-style: italic;\
color: #F8F8F8;\
background-color: #B52A1D\
}\
.ace-dawn .ace_invalid.ace_deprecated {\
text-decoration: underline;\
font-style: italic;\
color: #B52A1D\
}\
.ace-dawn .ace_support {\
color: #691C97\
}\
.ace-dawn .ace_support.ace_constant {\
color: #B4371F\
}\
.ace-dawn .ace_fold {\
background-color: #794938;\
border-color: #080808\
}\
.ace-dawn .ace_list,\
.ace-dawn .ace_markup.ace_list,\
.ace-dawn .ace_support.ace_function {\
color: #693A17\
}\
.ace-dawn .ace_storage {\
font-style: italic;\
color: #A71D5D\
}\
.ace-dawn .ace_string {\
color: #0B6125\
}\
.ace-dawn .ace_string.ace_regexp {\
color: #CF5628\
}\
.ace-dawn .ace_comment {\
font-style: italic;\
color: #5A525F\
}\
.ace-dawn .ace_heading,\
.ace-dawn .ace_markup.ace_heading {\
color: #19356D\
}\
.ace-dawn .ace_variable {\
color: #234A97\
}\
.ace-dawn .ace_indent-guide {\
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYLh/5+x/AAizA4hxNNsZAAAAAElFTkSuQmCC) right repeat-y\
}";

var dom = require("../lib/dom");
dom.importCssString(exports.cssText, exports.cssClass);
});
<commit_msg>Update tmp/bower_components/ace-builds/src/theme-dawn.js<commit_after><|endoftext|>


<commit_before>import { expect }              from 'chai';
import React                   from 'react';
import { buildBarriersConfig } from '../barrier';

describe('buildBarriersConfig', () => {
    it('Returns Undefined it contract has no barriers', () => {
        const contract = {
            "barrier_category":"euro_atm",
            "contract_category":"callput",
            "contract_category_display":"Up\/Down",
            "contract_display":"Higher",
            "contract_type":"CALL",
            "exchange_name":"FOREX",
            "expiry_type":"daily",
            "market":"forex",
            "max_contract_duration":"365d",
            "min_contract_duration":"1d",
            "sentiment":"up",
            "start_type":"spot",
            "submarket":"major_pairs",
            "underlying_symbol":"frxAUDJPY"
        };

        expect(buildBarriersConfig(contract)).to.eql(undefined);
    });

    it('Returns barriers with added values when contract has barrier but equals to zero', () => {
        const contract = {
            "barrier_category":"euro_atm",
            "barriers":0,
            "contract_category":"callput",
            "contract_category_display":"Up\/Down",
            "contract_display":"Higher",
            "contract_type":"CALL",
            "exchange_name":"FOREX",
            "expiry_type":"daily",
            "market":"forex",
            "max_contract_duration":"365d",
            "min_contract_duration":"1d",
            "sentiment":"up",
            "start_type":"spot",
            "submarket":"major_pairs",
            "underlying_symbol":"frxAUDJPY"
        };
        expect(buildBarriersConfig(contract)).to.eql(undefined);
    });

    it('Returns barriers with including empty object when contract has barriers but not values', () => {
        const contract = {
            "barrier_category":"euro_atm",
            "barriers":1,
            "contract_category":"callput",
            "contract_category_display":"Up\/Down",
            "contract_display":"Higher",
            "contract_type":"CALL",
            "exchange_name":"FOREX",
            "expiry_type":"daily",
            "market":"forex",
            "max_contract_duration":"365d",
            "min_contract_duration":"1d",
            "sentiment":"up",
            "start_type":"spot",
            "submarket":"major_pairs",
            "underlying_symbol":"frxAUDJPY"
        };
        expect(buildBarriersConfig(contract)).to.eql({
            count: 1,
            daily: {},
        });
    });

    it('Returns barriers with added values when contract has barriers', () => {
        const contract = {
            "barrier_category":"euro_atm",
            "barriers":1,
            "low_barrier": 22,
            "barrier": 33,
            "high_barrier": 44,
            "contract_category":"callput",
            "contract_category_display":"Up\/Down",
            "contract_display":"Higher",
            "contract_type":"CALL",
            "exchange_name":"FOREX",
            "expiry_type":"daily",
            "market":"forex",
            "max_contract_duration":"365d",
            "min_contract_duration":"1d",
            "sentiment":"up",
            "start_type":"spot",
            "submarket":"major_pairs",
            "underlying_symbol":"frxAUDJPY"
        };
        expect(buildBarriersConfig(contract)).to.eql({
            count: 1,
            daily: {
                "low_barrier": 22,
                "barrier": 33,
                "high_barrier": 44,
            },
        });
    });

    it('Returns barriers with some of the values when contract has barriers and some of the values', () => {
        const contract = {
            "barrier_category":"euro_atm",
            "barriers":1,
            "low_barrier": 22,
            "barrier": 33,
            "contract_category":"callput",
            "contract_category_display":"Up\/Down",
            "contract_display":"Higher",
            "contract_type":"CALL",
            "exchange_name":"FOREX",
            "expiry_type":"daily",
            "market":"forex",
            "max_contract_duration":"365d",
            "min_contract_duration":"1d",
            "sentiment":"up",
            "start_type":"spot",
            "submarket":"major_pairs",
            "underlying_symbol":"frxAUDJPY"
        };
        expect(buildBarriersConfig(contract)).to.eql({
            count: 1,
            daily: {
                "low_barrier": 22,
                "barrier": 33,
            },
        });
    });
});
<commit_msg>Update src/javascript/app_2/Stores/Modules/Trading/Helpers/__tests__/barrier.js<commit_after>import { expect }              from 'chai';
import React                   from 'react';
import { buildBarriersConfig } from '../barrier';

describe('buildBarriersConfig', () => {
    it('Returns Undefined if contract has no barriers', () => {
        const contract = {
            "barrier_category":"euro_atm",
            "contract_category":"callput",
            "contract_category_display":"Up\/Down",
            "contract_display":"Higher",
            "contract_type":"CALL",
            "exchange_name":"FOREX",
            "expiry_type":"daily",
            "market":"forex",
            "max_contract_duration":"365d",
            "min_contract_duration":"1d",
            "sentiment":"up",
            "start_type":"spot",
            "submarket":"major_pairs",
            "underlying_symbol":"frxAUDJPY"
        };

        expect(buildBarriersConfig(contract)).to.eql(undefined);
    });

    it('Returns barriers with added values when contract has barrier but equals to zero', () => {
        const contract = {
            "barrier_category":"euro_atm",
            "barriers":0,
            "contract_category":"callput",
            "contract_category_display":"Up\/Down",
            "contract_display":"Higher",
            "contract_type":"CALL",
            "exchange_name":"FOREX",
            "expiry_type":"daily",
            "market":"forex",
            "max_contract_duration":"365d",
            "min_contract_duration":"1d",
            "sentiment":"up",
            "start_type":"spot",
            "submarket":"major_pairs",
            "underlying_symbol":"frxAUDJPY"
        };
        expect(buildBarriersConfig(contract)).to.eql(undefined);
    });

    it('Returns barriers with including empty object when contract has barriers but not values', () => {
        const contract = {
            "barrier_category":"euro_atm",
            "barriers":1,
            "contract_category":"callput",
            "contract_category_display":"Up\/Down",
            "contract_display":"Higher",
            "contract_type":"CALL",
            "exchange_name":"FOREX",
            "expiry_type":"daily",
            "market":"forex",
            "max_contract_duration":"365d",
            "min_contract_duration":"1d",
            "sentiment":"up",
            "start_type":"spot",
            "submarket":"major_pairs",
            "underlying_symbol":"frxAUDJPY"
        };
        expect(buildBarriersConfig(contract)).to.eql({
            count: 1,
            daily: {},
        });
    });

    it('Returns barriers with added values when contract has barriers', () => {
        const contract = {
            "barrier_category":"euro_atm",
            "barriers":1,
            "low_barrier": 22,
            "barrier": 33,
            "high_barrier": 44,
            "contract_category":"callput",
            "contract_category_display":"Up\/Down",
            "contract_display":"Higher",
            "contract_type":"CALL",
            "exchange_name":"FOREX",
            "expiry_type":"daily",
            "market":"forex",
            "max_contract_duration":"365d",
            "min_contract_duration":"1d",
            "sentiment":"up",
            "start_type":"spot",
            "submarket":"major_pairs",
            "underlying_symbol":"frxAUDJPY"
        };
        expect(buildBarriersConfig(contract)).to.eql({
            count: 1,
            daily: {
                "low_barrier": 22,
                "barrier": 33,
                "high_barrier": 44,
            },
        });
    });

    it('Returns barriers with some of the values when contract has barriers and some of the values', () => {
        const contract = {
            "barrier_category":"euro_atm",
            "barriers":1,
            "low_barrier": 22,
            "barrier": 33,
            "contract_category":"callput",
            "contract_category_display":"Up\/Down",
            "contract_display":"Higher",
            "contract_type":"CALL",
            "exchange_name":"FOREX",
            "expiry_type":"daily",
            "market":"forex",
            "max_contract_duration":"365d",
            "min_contract_duration":"1d",
            "sentiment":"up",
            "start_type":"spot",
            "submarket":"major_pairs",
            "underlying_symbol":"frxAUDJPY"
        };
        expect(buildBarriersConfig(contract)).to.eql({
            count: 1,
            daily: {
                "low_barrier": 22,
                "barrier": 33,
            },
        });
    });
});
<|endoftext|>


<commit_before>import Newsletter from '../namespace.js';
import moment from 'moment';

SyncedCron.options = {
  log: true,
  collectionName: 'cronHistory',
  utc: false,
  collectionTTL: 172800
};

const addZero = num => {
  return num < 10 ? "0"+num : num;
};

var defaultFrequency = 7; // once a week
var defaultTime = '00:00'; // GMT

var getSchedule = function (parser) {
  var frequency = Telescope.settings.get('newsletterFrequency', defaultFrequency);
  var recur = parser.recur();
  var schedule;

  // Default is once a week (Mondays)
  if (!!frequency) {
    schedule = recur.on(frequency).dayOfWeek();
  }
  else {
    schedule = recur.on(2).dayOfWeek();
  }

  const offsetInMinutes = new Date().getTimezoneOffset();
  const GMTtime = moment.duration(Telescope.settings.get('newsletterTime', defaultTime));
  const serverTime = GMTtime.subtract(offsetInMinutes, "minutes");
  const serverTimeString = addZero(serverTime.hours()) + ":" + addZero(serverTime.minutes());

  console.log("// scheduled for: (GMT): "+Telescope.settings.get('newsletterTime', defaultTime));
  console.log("// server offset (minutes): "+offsetInMinutes);
  console.log("// server scheduled time (minutes): "+serverTime.asMinutes());
  console.log("// server scheduled time: "+serverTimeString);

  return schedule.on(serverTimeString).time();
};

Meteor.methods({
  getNextJob: function () {
    var nextJob = SyncedCron.nextScheduledAtDate('scheduleNewsletter');
    console.log(nextJob);
    return nextJob;
  }
});

var addJob = function () {
  SyncedCron.add({
    name: 'scheduleNewsletter',
    schedule: function(parser) {
      // parser is a later.parse object
      return getSchedule(parser);
    },
    job: function() {
      // only schedule newsletter campaigns in production
      if (process.env.NODE_ENV === "production" || Telescope.settings.get("enableNewsletterInDev", false)) {
        console.log("// Scheduling newsletter…")
        console.log(new Date());
        Newsletter.scheduleNextWithMailChimp();
      }
    }
  });
};

Meteor.startup(function () {
  if (Telescope.settings.get('enableNewsletter', true) && Telescope.settings.get('mailChimpAPIKey') && Telescope.settings.get('mailChimpListId')) {
    addJob();
  }
});
<commit_msg>fix newsletter frequency bug?<commit_after>import Newsletter from '../namespace.js';
import moment from 'moment';

const defaultFrequency = [1]; // every monday
const defaultTime = '00:00'; // GMT

SyncedCron.options = {
  log: true,
  collectionName: 'cronHistory',
  utc: false,
  collectionTTL: 172800
};

const addZero = num => {
  return num < 10 ? "0"+num : num;
};

var getSchedule = function (parser) {
  var frequency = Telescope.settings.get('newsletterFrequency', defaultFrequency);
  var recur = parser.recur();
  var schedule;

  // Default is once a week (Mondays)
  if (!!frequency) {
    schedule = recur.on(frequency).dayOfWeek();
  }
  else {
    schedule = recur.on(2).dayOfWeek();
  }

  const offsetInMinutes = new Date().getTimezoneOffset();
  const GMTtime = moment.duration(Telescope.settings.get('newsletterTime', defaultTime));
  const serverTime = GMTtime.subtract(offsetInMinutes, "minutes");
  const serverTimeString = addZero(serverTime.hours()) + ":" + addZero(serverTime.minutes());

  console.log("// scheduled for: (GMT): "+Telescope.settings.get('newsletterTime', defaultTime));
  console.log("// server offset (minutes): "+offsetInMinutes);
  console.log("// server scheduled time (minutes): "+serverTime.asMinutes());
  console.log("// server scheduled time: "+serverTimeString);

  return schedule.on(serverTimeString).time();
};

Meteor.methods({
  getNextJob: function () {
    var nextJob = SyncedCron.nextScheduledAtDate('scheduleNewsletter');
    console.log(nextJob);
    return nextJob;
  }
});

var addJob = function () {
  SyncedCron.add({
    name: 'scheduleNewsletter',
    schedule: function(parser) {
      // parser is a later.parse object
      return getSchedule(parser);
    },
    job: function() {
      // only schedule newsletter campaigns in production
      if (process.env.NODE_ENV === "production" || Telescope.settings.get("enableNewsletterInDev", false)) {
        console.log("// Scheduling newsletter…")
        console.log(new Date());
        Newsletter.scheduleNextWithMailChimp();
      }
    }
  });
};

Meteor.startup(function () {
  if (Telescope.settings.get('enableNewsletter', true) && Telescope.settings.get('mailChimpAPIKey') && Telescope.settings.get('mailChimpListId')) {
    addJob();
  }
});
<|endoftext|>