<commit_before>(function() {

  QUnit.module('Backbone.Events');

  QUnit.test('on and trigger', function(assert) {
    assert.expect(2);
    var obj = {counter: 0};
    _.extend(obj, Backbone.Events);
    obj.on('event', function() { obj.counter += 1; });
    obj.trigger('event');
    assert.equal(obj.counter, 1, 'counter should be incremented.');
    obj.trigger('event');
    obj.trigger('event');
    obj.trigger('event');
    obj.trigger('event');
    assert.equal(obj.counter, 5, 'counter should be incremented five times.');
  });

  QUnit.test('binding and triggering multiple events', function(assert) {
    assert.expect(4);
    var obj = {counter: 0};
    _.extend(obj, Backbone.Events);

    obj.on('a b c', function() { obj.counter += 1; });

    obj.trigger('a');
    assert.equal(obj.counter, 1);

    obj.trigger('a b');
    assert.equal(obj.counter, 3);

    obj.trigger('c');
    assert.equal(obj.counter, 4);

    obj.off('a c');
    obj.trigger('a b c');
    assert.equal(obj.counter, 5);
  });

  QUnit.test('binding and triggering with event maps', function(assert) {
    var obj = {counter: 0};
    _.extend(obj, Backbone.Events);

    var increment = function() {
      this.counter += 1;
    };

    obj.on({
      a: increment,
      b: increment,
      c: increment
    }, obj);

    obj.trigger('a');
    assert.equal(obj.counter, 1);

    obj.trigger('a b');
    assert.equal(obj.counter, 3);

    obj.trigger('c');
    assert.equal(obj.counter, 4);

    obj.off({
      a: increment,
      c: increment
    }, obj);
    obj.trigger('a b c');
    assert.equal(obj.counter, 5);
  });

  QUnit.test('binding and triggering multiple event names with event maps', function(assert) {
    var obj = {counter: 0};
    _.extend(obj, Backbone.Events);

    var increment = function() {
      this.counter += 1;
    };

    obj.on({
      'a b c': increment
    });

    obj.trigger('a');
    assert.equal(obj.counter, 1);

    obj.trigger('a b');
    assert.equal(obj.counter, 3);

    obj.trigger('c');
    assert.equal(obj.counter, 4);

    obj.off({
      'a c': increment
    });
    obj.trigger('a b c');
    assert.equal(obj.counter, 5);
  });

  QUnit.test('binding and trigger with event maps context', function(assert) {
    assert.expect(2);
    var obj = {counter: 0};
    var context = {};
    _.extend(obj, Backbone.Events);

    obj.on({
      a: function() {
        assert.strictEqual(this, context, 'defaults `context` to `callback` param');
      }
    }, context).trigger('a');

    obj.off().on({
      a: function() {
        assert.strictEqual(this, context, 'will not override explicit `context` param');
      }
    }, this, context).trigger('a');
  });

  QUnit.test('listenTo and stopListening', function(assert) {
    assert.expect(1);
    var a = _.extend({}, Backbone.Events);
    var b = _.extend({}, Backbone.Events);
    a.listenTo(b, 'all', function(){ assert.ok(true); });
    b.trigger('anything');
    a.listenTo(b, 'all', function(){ assert.ok(false); });
    a.stopListening();
    b.trigger('anything');
  });

  QUnit.test('listenTo and stopListening with event maps', function(assert) {
    assert.expect(4);
    var a = _.extend({}, Backbone.Events);
    var b = _.extend({}, Backbone.Events);
    var cb = function(){ assert.ok(true); };
    a.listenTo(b, {event: cb});
    b.trigger('event');
    a.listenTo(b, {event2: cb});
    b.on('event2', cb);
    a.stopListening(b, {event2: cb});
    b.trigger('event event2');
    a.stopListening();
    b.trigger('event event2');
  });

  QUnit.test('stopListening with omitted args', function(assert) {
    assert.expect(2);
    var a = _.extend({}, Backbone.Events);
    var b = _.extend({}, Backbone.Events);
    var cb = function() { assert.ok(true); };
    a.listenTo(b, 'event', cb);
    b.on('event', cb);
    a.listenTo(b, 'event2', cb);
    a.stopListening(null, {event: cb});
    b.trigger('event event2');
    b.off();
    a.listenTo(b, 'event event2', cb);
    a.stopListening(null, 'event');
    a.stopListening();
    b.trigger('event2');
  });

  QUnit.test('listenToOnce', function(assert) {
    assert.expect(2);
    // Same as the previous test, but we use once rather than having to explicitly unbind
    var obj = {counterA: 0, counterB: 0};
    _.extend(obj, Backbone.Events);
    var incrA = function(){ obj.counterA += 1; obj.trigger('event'); };
    var incrB = function(){ obj.counterB += 1; };
    obj.listenToOnce(obj, 'event', incrA);
    obj.listenToOnce(obj, 'event', incrB);
    obj.trigger('event');
    assert.equal(obj.counterA, 1, 'counterA should have only been incremented once.');
    assert.equal(obj.counterB, 1, 'counterB should have only been incremented once.');
  });

  QUnit.test('listenToOnce and stopListening', function(assert) {
    assert.expect(1);
    var a = _.extend({}, Backbone.Events);
    var b = _.extend({}, Backbone.Events);
    a.listenToOnce(b, 'all', function() { assert.ok(true); });
    b.trigger('anything');
    b.trigger('anything');
    a.listenToOnce(b, 'all', function() { assert.ok(false); });
    a.stopListening();
    b.trigger('anything');
  });

  QUnit.test('listenTo, listenToOnce and stopListening', function(assert) {
    assert.expect(1);
    var a = _.extend({}, Backbone.Events);
    var b = _.extend({}, Backbone.Events);
    a.listenToOnce(b, 'all', function() { assert.ok(true); });
    b.trigger('anything');
    b.trigger('anything');
    a.listenTo(b, 'all', function() { assert.ok(false); });
    a.stopListening();
    b.trigger('anything');
  });

  QUnit.test('listenTo and stopListening with event maps', function(assert) {
    assert.expect(1);
    var a = _.extend({}, Backbone.Events);
    var b = _.extend({}, Backbone.Events);
    a.listenTo(b, {change: function(){ assert.ok(true); }});
    b.trigger('change');
    a.listenTo(b, {change: function(){ assert.ok(false); }});
    a.stopListening();
    b.trigger('change');
  });

  QUnit.test('listenTo yourself', function(assert) {
    assert.expect(1);
    var e = _.extend({}, Backbone.Events);
    e.listenTo(e, 'foo', function(){ assert.ok(true); });
    e.trigger('foo');
  });

  QUnit.test('listenTo yourself cleans yourself up with stopListening', function(assert) {
    assert.expect(1);
    var e = _.extend({}, Backbone.Events);
    e.listenTo(e, 'foo', function(){ assert.ok(true); });
    e.trigger('foo');
    e.stopListening();
    e.trigger('foo');
  });

  QUnit.test('stopListening cleans up references', function(assert) {
    assert.expect(12);
    var a = _.extend({}, Backbone.Events);
    var b = _.extend({}, Backbone.Events);
    var fn = function() {};
    b.on('event', fn);
    a.listenTo(b, 'event', fn).stopListening();
    assert.equal(_.size(a._listeningTo), 0);
    assert.equal(_.size(b._events.event), 1);
    assert.equal(_.size(b._listeners), 0);
    a.listenTo(b, 'event', fn).stopListening(b);
    assert.equal(_.size(a._listeningTo), 0);
    assert.equal(_.size(b._events.event), 1);
    assert.equal(_.size(b._listeners), 0);
    a.listenTo(b, 'event', fn).stopListening(b, 'event');
    assert.equal(_.size(a._listeningTo), 0);
    assert.equal(_.size(b._events.event), 1);
    assert.equal(_.size(b._listeners), 0);
    a.listenTo(b, 'event', fn).stopListening(b, 'event', fn);
    assert.equal(_.size(a._listeningTo), 0);
    assert.equal(_.size(b._events.event), 1);
    assert.equal(_.size(b._listeners), 0);
  });

  QUnit.test('stopListening cleans up references from listenToOnce', function(assert) {
    assert.expect(12);
    var a = _.extend({}, Backbone.Events);
    var b = _.extend({}, Backbone.Events);
    var fn = function() {};
    b.on('event', fn);
    a.listenToOnce(b, 'event', fn).stopListening();
    assert.equal(_.size(a._listeningTo), 0);
    assert.equal(_.size(b._events.event), 1);
    assert.equal(_.size(b._listeners), 0);
    a.listenToOnce(b, 'event', fn).stopListening(b);
    assert.equal(_.size(a._listeningTo), 0);
    assert.equal(_.size(b._events.event), 1);
    assert.equal(_.size(b._listeners), 0);
    a.listenToOnce(b, 'event', fn).stopListening(b, 'event');
    assert.equal(_.size(a._listeningTo), 0);
    assert.equal(_.size(b._events.event), 1);
    assert.equal(_.size(b._listeners), 0);
    a.listenToOnce(b, 'event', fn).stopListening(b, 'event', fn);
    assert.equal(_.size(a._listeningTo), 0);
    assert.equal(_.size(b._events.event), 1);
    assert.equal(_.size(b._listeners), 0);
  });

  QUnit.test('listenTo and off cleaning up references', function(assert) {
    assert.expect(8);
    var a = _.extend({}, Backbone.Events);
    var b = _.extend({}, Backbone.Events);
    var fn = function() {};
    a.listenTo(b, 'event', fn);
    b.off();
    assert.equal(_.size(a._listeningTo), 0);
    assert.equal(_.size(b._listeners), 0);
    a.listenTo(b, 'event', fn);
    b.off('event');
    assert.equal(_.size(a._listeningTo), 0);
    assert.equal(_.size(b._listeners), 0);
    a.listenTo(b, 'event', fn);
    b.off(null, fn);
    assert.equal(_.size(a._listeningTo), 0);
    assert.equal(_.size(b._listeners), 0);
    a.listenTo(b, 'event', fn);
    b.off(null, null, a);
    assert.equal(_.size(a._listeningTo), 0);
    assert.equal(_.size(b._listeners), 0);
  });

  QUnit.test('listenTo and stopListening cleaning up references', function(assert) {
    assert.expect(2);
    var a = _.extend({}, Backbone.Events);
    var b = _.extend({}, Backbone.Events);
    a.listenTo(b, 'all', function(){ assert.ok(true); });
    b.trigger('anything');
    a.listenTo(b, 'other', function(){ assert.ok(false); });
    a.stopListening(b, 'other');
    a.stopListening(b, 'all');
    assert.equal(_.size(a._listeningTo), 0);
  });

  QUnit.test('listenToOnce without context cleans up references after the event has fired', function(assert) {
    assert.expect(2);
    var a = _.extend({}, Backbone.Events);
    var b = _.extend({}, Backbone.Events);
    a.listenToOnce(b, 'all', function(){ assert.ok(true); });
    b.trigger('anything');
    assert.equal(_.size(a._listeningTo), 0);
  });

  QUnit.test('listenToOnce with event maps cleans up references', function(assert) {
    assert.expect(2);
    var a = _.extend({}, Backbone.Events);
    var b = _.extend({}, Backbone.Events);
    a.listenToOnce(b, {
      one: function() { assert.ok(true); },
      two: function() { assert.ok(false); }
    });
    b.trigger('one');
    assert.equal(_.size(a._listeningTo), 1);
  });

  QUnit.test('listenToOnce with event maps binds the correct `this`', function(assert) {
    assert.expect(1);
    var a = _.extend({}, Backbone.Events);
    var b = _.extend({}, Backbone.Events);
    a.listenToOnce(b, {
      one: function() { assert.ok(this === a); },
      two: function() { assert.ok(false); }
    });
    b.trigger('one');
  });

  QUnit.test("listenTo with empty callback doesn't throw an error", function(assert) {
    assert.expect(1);
    var e = _.extend({}, Backbone.Events);
    e.listenTo(e, 'foo', null);
    e.trigger('foo');
    assert.ok(true);
  });

  QUnit.test('trigger all for each event', function(assert) {
    assert.expect(3);
    var a, b, obj = {counter: 0};
    _.extend(obj, Backbone.Events);
    obj.on('all', function(event) {
      obj.counter++;
      if (event === 'a') a = true;
      if (event === 'b') b = true;
    })
    .trigger('a b');
    assert.ok(a);
    assert.ok(b);
    assert.equal(obj.counter, 2);
  });

  QUnit.test('on, then unbind all functions', function(assert) {
    assert.expect(1);
    var obj = {counter: 0};
    _.extend(obj, Backbone.Events);
    var callback = function() { obj.counter += 1; };
    obj.on('event', callback);
    obj.trigger('event');
    obj.off('event');
    obj.trigger('event');
    assert.equal(obj.counter, 1, 'counter should have only been incremented once.');
  });

  QUnit.test('bind two callbacks, unbind only one', function(assert) {
    assert.expect(2);
    var obj = {counterA: 0, counterB: 0};
    _.extend(obj, Backbone.Events);
    var callback = function() { obj.counterA += 1; };
    obj.on('event', callback);
    obj.on('event', function() { obj.counterB += 1; });
    obj.trigger('event');
    obj.off('event', callback);
    obj.trigger('event');
    assert.equal(obj.counterA, 1, 'counterA should have only been incremented once.');
    assert.equal(obj.counterB, 2, 'counterB should have been incremented twice.');
  });

  QUnit.test('unbind a callback in the midst of it firing', function(assert) {
    assert.expect(1);
    var obj = {counter: 0};
    _.extend(obj, Backbone.Events);
    var callback = function() {
      obj.counter += 1;
      obj.off('event', callback);
    };
    obj.on('event', callback);
    obj.trigger('event');
    obj.trigger('event');
    obj.trigger('event');
    assert.equal(obj.counter, 1, 'the callback should have been unbound.');
  });

  QUnit.test('two binds that unbind themeselves', function(assert) {
    assert.expect(2);
    var obj = {counterA: 0, counterB: 0};
    _.extend(obj, Backbone.Events);
    var incrA = function(){ obj.counterA += 1; obj.off('event', incrA); };
    var incrB = function(){ obj.counterB += 1; obj.off('event', incrB); };
    obj.on('event', incrA);
    obj.on('event', incrB);
    obj.trigger('event');
    obj.trigger('event');
    obj.trigger('event');
    assert.equal(obj.counterA, 1, 'counterA should have only been incremented once.');
    assert.equal(obj.counterB, 1, 'counterB should have only been incremented once.');
  });

  QUnit.test('bind a callback with a default context when none supplied', function(assert) {
    assert.expect(1);
    var obj = _.extend({
      assertTrue: function() {
        assert.equal(this, obj, '`this` was bound to the callback');
      }
    }, Backbone.Events);

    obj.once('event', obj.assertTrue);
    obj.trigger('event');
  });

  QUnit.test('bind a callback with a supplied context', function(assert) {
    assert.expect(1);
    var TestClass = function() {
      return this;
    };
    TestClass.prototype.assertTrue = function() {
      assert.ok(true, '`this` was bound to the callback');
    };

    var obj = _.extend({}, Backbone.Events);
    obj.on('event', function() { this.assertTrue(); }, new TestClass);
    obj.trigger('event');
  });

  QUnit.test('nested trigger with unbind', function(assert) {
    assert.expect(1);
    var obj = {counter: 0};
    _.extend(obj, Backbone.Events);
    var incr1 = function(){ obj.counter += 1; obj.off('event', incr1); obj.trigger('event'); };
    var incr2 = function(){ obj.counter += 1; };
    obj.on('event', incr1);
    obj.on('event', incr2);
    obj.trigger('event');
    assert.equal(obj.counter, 3, 'counter should have been incremented three times');
  });

  QUnit.test('callback list is not altered during trigger', function(assert) {
    assert.expect(2);
    var counter = 0, obj = _.extend({}, Backbone.Events);
    var incr = function(){ counter++; };
    var incrOn = function(){ obj.on('event all', incr); };
    var incrOff = function(){ obj.off('event all', incr); };

    obj.on('event all', incrOn).trigger('event');
    assert.equal(counter, 0, 'on does not alter callback list');

    obj.off().on('event', incrOff).on('event all', incr).trigger('event');
    assert.equal(counter, 2, 'off does not alter callback list');
  });

  QUnit.test("#1282 - 'all' callback list is retrieved after each event.", function(assert) {
    assert.expect(1);
    var counter = 0;
    var obj = _.extend({}, Backbone.Events);
    var incr = function(){ counter++; };
    obj.on('x', function() {
      obj.on('y', incr).on('all', incr);
    })
    .trigger('x y');
    assert.strictEqual(counter, 2);
  });

  QUnit.test('if no callback is provided, `on` is a noop', function(assert) {
    assert.expect(0);
    _.extend({}, Backbone.Events).on('test').trigger('test');
  });

  QUnit.test('if callback is truthy but not a function, `on` should throw an error just like jQuery', function(assert) {
    assert.expect(1);
    var view = _.extend({}, Backbone.Events).on('test', 'noop');
    assert.raises(function() {
      view.trigger('test');
    });
  });

  QUnit.test('remove all events for a specific context', function(assert) {
    assert.expect(4);
    var obj = _.extend({}, Backbone.Events);
    obj.on('x y all', function() { assert.ok(true); });
    obj.on('x y all', function() { assert.ok(false); }, obj);
    obj.off(null, null, obj);
    obj.trigger('x y');
  });

  QUnit.test('remove all events for a specific callback', function(assert) {
    assert.expect(4);
    var obj = _.extend({}, Backbone.Events);
    var success = function() { assert.ok(true); };
    var fail = function() { assert.ok(false); };
    obj.on('x y all', success);
    obj.on('x y all', fail);
    obj.off(null, fail);
    obj.trigger('x y');
  });

  QUnit.test('#1310 - off does not skip consecutive events', function(assert) {
    assert.expect(0);
    var obj = _.extend({}, Backbone.Events);
    obj.on('event', function() { assert.ok(false); }, obj);
    obj.on('event', function() { assert.ok(false); }, obj);
    obj.off(null, null, obj);
    obj.trigger('event');
  });

  QUnit.test('once', function(assert) {
    assert.expect(2);
    // Same as the previous test, but we use once rather than having to explicitly unbind
    var obj = {counterA: 0, counterB: 0};
    _.extend(obj, Backbone.Events);
    var incrA = function(){ obj.counterA += 1; obj.trigger('event'); };
    var incrB = function(){ obj.counterB += 1; };
    obj.once('event', incrA);
    obj.once('event', incrB);
    obj.trigger('event');
    assert.equal(obj.counterA, 1, 'counterA should have only been incremented once.');
    assert.equal(obj.counterB, 1, 'counterB should have only been incremented once.');
  });

  QUnit.test('once variant one', function(assert) {
    assert.expect(3);
    var f = function(){ assert.ok(true); };

    var a = _.extend({}, Backbone.Events).once('event', f);
    var b = _.extend({}, Backbone.Events).on('event', f);

    a.trigger('event');

    b.trigger('event');
    b.trigger('event');
  });

  QUnit.test('once variant two', function(assert) {
    assert.expect(3);
    var f = function(){ assert.ok(true); };
    var obj = _.extend({}, Backbone.Events);

    obj
      .once('event', f)
      .on('event', f)
      .trigger('event')
      .trigger('event');
  });

  QUnit.test('once with off', function(assert) {
    assert.expect(0);
    var f = function(){ assert.ok(true); };
    var obj = _.extend({}, Backbone.Events);

    obj.once('event', f);
    obj.off('event', f);
    obj.trigger('event');
  });

  QUnit.test('once with event maps', function(assert) {
    var obj = {counter: 0};
    _.extend(obj, Backbone.Events);

    var increment = function() {
      this.counter += 1;
    };

    obj.once({
      a: increment,
      b: increment,
      c: increment
    }, obj);

    obj.trigger('a');
    assert.equal(obj.counter, 1);

    obj.trigger('a b');
    assert.equal(obj.counter, 2);

    obj.trigger('c');
    assert.equal(obj.counter, 3);

    obj.trigger('a b c');
    assert.equal(obj.counter, 3);
  });

  QUnit.test('bind a callback with a supplied context using once with object notation', function(assert) {
    assert.expect(1);
    var obj = {counter: 0};
    var context = {};
    _.extend(obj, Backbone.Events);

    obj.once({
      a: function() {
        assert.strictEqual(this, context, 'defaults `context` to `callback` param');
      }
    }, context).trigger('a');
  });

  QUnit.test('once with off only by context', function(assert) {
    assert.expect(0);
    var context = {};
    var obj = _.extend({}, Backbone.Events);
    obj.once('event', function(){ assert.ok(false); }, context);
    obj.off(null, null, context);
    obj.trigger('event');
  });

  QUnit.test('Backbone object inherits Events', function(assert) {
    assert.ok(Backbone.on === Backbone.Events.on);
  });

  QUnit.test('once with asynchronous events', function(assert) {
    var done = assert.async();
    assert.expect(1);
    var func = _.debounce(function() { assert.ok(true); done(); }, 50);
    var obj = _.extend({}, Backbone.Events).once('async', func);

    obj.trigger('async');
    obj.trigger('async');
  });

  QUnit.test('once with multiple events.', function(assert) {
    assert.expect(2);
    var obj = _.extend({}, Backbone.Events);
    obj.once('x y', function() { assert.ok(true); });
    obj.trigger('x y');
  });

  QUnit.test('Off during iteration with once.', function(assert) {
    assert.expect(2);
    var obj = _.extend({}, Backbone.Events);
    var f = function(){ this.off('event', f); };
    obj.on('event', f);
    obj.once('event', function(){});
    obj.on('event', function(){ assert.ok(true); });

    obj.trigger('event');
    obj.trigger('event');
  });

  QUnit.test('`once` on `all` should work as expected', function(assert) {
    assert.expect(1);
    Backbone.once('all', function() {
      assert.ok(true);
      Backbone.trigger('all');
    });
    Backbone.trigger('all');
  });

  QUnit.test('once without a callback is a noop', function(assert) {
    assert.expect(0);
    _.extend({}, Backbone.Events).once('event').trigger('event');
  });

  QUnit.test('listenToOnce without a callback is a noop', function(assert) {
    assert.expect(0);
    var obj = _.extend({}, Backbone.Events);
    obj.listenToOnce(obj, 'event').trigger('event');
  });

  QUnit.test('event functions are chainable', function(assert) {
    var obj = _.extend({}, Backbone.Events);
    var obj2 = _.extend({}, Backbone.Events);
    var fn = function() {};
    assert.equal(obj, obj.trigger('noeventssetyet'));
    assert.equal(obj, obj.off('noeventssetyet'));
    assert.equal(obj, obj.stopListening('noeventssetyet'));
    assert.equal(obj, obj.on('a', fn));
    assert.equal(obj, obj.once('c', fn));
    assert.equal(obj, obj.trigger('a'));
    assert.equal(obj, obj.listenTo(obj2, 'a', fn));
    assert.equal(obj, obj.listenToOnce(obj2, 'b', fn));
    assert.equal(obj, obj.off('a c'));
    assert.equal(obj, obj.stopListening(obj2, 'a'));
    assert.equal(obj, obj.stopListening());
  });

  QUnit.test('#3448 - listenToOnce with space-separated events', function(assert) {
    assert.expect(2);
    var one = _.extend({}, Backbone.Events);
    var two = _.extend({}, Backbone.Events);
    var count = 1;
    one.listenToOnce(two, 'x y', function(n) { assert.ok(n === count++); });
    two.trigger('x', 1);
    two.trigger('x', 1);
    two.trigger('y', 2);
    two.trigger('y', 2);
  });

})();
<commit_msg>Update tmp/bower_components/lodash/vendor/backbone/test/events.js<commit_after><|endoftext|>


<commit_before>define([
    'jquery',
    'underscore',
    'backbone',
    'app',
    'simplemde',
    'models/testcase/TestCaseModel',
    'text!templates/testcases/testCaseTemplate.html'
], function($, _, Backbone, app, SimpleMDE, TestCaseModel, testCaseTemplate) {

    var TestCaseView = Backbone.View.extend({

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

        initialize: function() {
            _.bindAll(this, 'render', 'save');
            this.project_id    = 0;
            this.test_suite_id = 0;
            this.test_case_id  = 0;
        },

        render: function(options) {
            $('.item').removeClass('active');
            $('.item a[href="#/specification"]').parent().addClass('active');

            this.model = options.model;
            var executionTypes = options.execution_types;
            this.projectId   = options.project_id;
            this.testSuiteId = options.test_suite_id;
            this.testCaseId  = options.test_case_id;
            var data = {
                testcase: this.model,
                projectId: options.project_id,
                testSuiteId: options.test_suite_id,
                testCaseId: options.test_case_id,
                execution_types: executionTypes,
                _: _
            }
            var compiledTemplate = _.template(testCaseTemplate, data);
            this.$el.html(compiledTemplate);
            this.description_simplemde = new SimpleMDE({
                autoDownloadFontAwesome: true,
                autofocus: false,
                autosave: {
                    enabled: false
                },
                element: this.$('#testcase-description-input')[0],
                indentWithTabs: false,
                spellChecker: false,
                tabSize: 4
            });
            this.prerequisite_simplemde = new SimpleMDE({
                autoDownloadFontAwesome: true,
                autofocus: false,
                autosave: {
                    enabled: false
                },
                element: this.$('#testcase-prerequisite-input')[0],
                indentWithTabs: false,
                spellChecker: false,
                tabSize: 4
            });
        },

        save: function(event) {
            event.preventDefault();
            event.stopPropagation();

            var self = this;

            if (this.$("#testcase-form").parsley().validate()) {
                this.model.save({
                    name: this.$("#testcase-name-input").val(),
                    description: this.description_simplemde.value(),
                    prerequisite: this.prerequisite_simplemde.value(),
                    execution_type_id: this.$("#testcase-executiontype_id-input").val(),
                    test_suite_id: this.testSuiteId,
                    test_case_id: this.testCaseId,
                    project_id: this.projectId,
                    created_by: app.session.user_id
                }, {
                    wait: false,
                    success: function(mod, res) {
                        app.showAlert('Success!', 'Test case ' + this.$("#testcase-name-input").val() + ' updated!', 'success')
                        Backbone.trigger('nestor:navigationtree_changed');
                        Backbone.history.navigate("#/projects/" + self.projectId + '/testsuites/' + self.testSuiteId + '/testcases/' + self.testCaseId + '/view', {
                            trigger: false
                        });
                    },
                    error: function(model, response, options) {
                        var message = _.has(response, 'statusText') ? response.statusText : 'Unknown error!';
                        if (
                            _.has(response, 'responseJSON') &&
                            _.has(response.responseJSON, 'name') &&
                            _.has(response.responseJSON.name, 'length') &&
                            response.responseJSON.name.length > 0
                        ) {
                            message = response.responseJSON.name[0];
                        }
                        app.showAlert('Failed to add new Test Case', message, 'error');
                    }
                });
            } else {
                if (typeof DEBUG != 'undefined' && DEBUG) console.log("Did not pass clientside validation");
            }

            return false;
        }

    });

    return TestCaseView;

});<commit_msg>Use click event handler instead of form submit<commit_after>define([
    'jquery',
    'underscore',
    'backbone',
    'app',
    'simplemde',
    'models/testcase/TestCaseModel',
    'text!templates/testcases/testCaseTemplate.html'
], function($, _, Backbone, app, SimpleMDE, TestCaseModel, testCaseTemplate) {

    var TestCaseView = Backbone.View.extend({

        events: {
            'click #new-testcase-btn': 'save'
        },

        initialize: function() {
            _.bindAll(this, 'render', 'save');
            this.project_id    = 0;
            this.test_suite_id = 0;
            this.test_case_id  = 0;
        },

        render: function(options) {
            $('.item').removeClass('active');
            $('.item a[href="#/specification"]').parent().addClass('active');

            this.model = options.model;
            var executionTypes = options.execution_types;
            this.projectId   = options.project_id;
            this.testSuiteId = options.test_suite_id;
            this.testCaseId  = options.test_case_id;
            var data = {
                testcase: this.model,
                projectId: options.project_id,
                testSuiteId: options.test_suite_id,
                testCaseId: options.test_case_id,
                execution_types: executionTypes,
                _: _
            }
            var compiledTemplate = _.template(testCaseTemplate, data);
            this.$el.html(compiledTemplate);
            this.description_simplemde = new SimpleMDE({
                autoDownloadFontAwesome: true,
                autofocus: false,
                autosave: {
                    enabled: false
                },
                element: this.$('#testcase-description-input')[0],
                indentWithTabs: false,
                spellChecker: false,
                tabSize: 4
            });
            this.prerequisite_simplemde = new SimpleMDE({
                autoDownloadFontAwesome: true,
                autofocus: false,
                autosave: {
                    enabled: false
                },
                element: this.$('#testcase-prerequisite-input')[0],
                indentWithTabs: false,
                spellChecker: false,
                tabSize: 4
            });
        },

        save: function(event) {
            var self = this;

            if (this.$("#testcase-form").parsley().validate()) {
                this.model.save({
                    name: this.$("#testcase-name-input").val(),
                    description: this.description_simplemde.value(),
                    prerequisite: this.prerequisite_simplemde.value(),
                    execution_type_id: this.$("#testcase-executiontype_id-input").val(),
                    test_suite_id: this.testSuiteId,
                    test_case_id: this.testCaseId,
                    project_id: this.projectId,
                    created_by: app.session.user_id
                }, {
                    wait: false,
                    success: function(mod, res) {
                        app.showAlert('Success!', 'Test case ' + this.$("#testcase-name-input").val() + ' updated!', 'success')
                        Backbone.trigger('nestor:navigationtree_changed');
                        Backbone.history.navigate("#/projects/" + self.projectId + '/testsuites/' + self.testSuiteId + '/testcases/' + self.testCaseId + '/view', {
                            trigger: false
                        });
                    },
                    error: function(model, response, options) {
                        var message = _.has(response, 'statusText') ? response.statusText : 'Unknown error!';
                        if (
                            _.has(response, 'responseJSON') &&
                            _.has(response.responseJSON, 'name') &&
                            _.has(response.responseJSON.name, 'length') &&
                            response.responseJSON.name.length > 0
                        ) {
                            message = response.responseJSON.name[0];
                        }
                        app.showAlert('Failed to add new Test Case', message, 'error');
                    }
                });
            } else {
                if (typeof DEBUG != 'undefined' && DEBUG) console.log("Did not pass clientside validation");
            }

            return false;
        }

    });

    return TestCaseView;

});
<|endoftext|>


<commit_before>var fs 				= require('fs-extra');
var http 			= require('http'); // http protocol
var https 			= require('https'); // https protocol
var Mongo      		= require('mongodb').MongoClient;
var express 		= require('express'); // web server
var cookieParser 	= require('cookie-parser'); // parse cookies
var socketio 		= require('socket.io'); // websocket
var request 		= require('request'); // http trafficer
var bodyParser 		= require('body-parser'); // middleware
// Helmet

// web server
var app = express();
app.use(cookieParser());
var server = http.Server(app);
var io = socketio(server);

app.use('/', express.static('../Client/'));

var credentials = {
    key:  fs.readFileSync('bin/key.pem'),
    cert: fs.readFileSync('bin/cert.pem')
};

// body parsing ensures req.body property
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

// error handling middleware
var errorHandler = function(err, req, res, next) {
    if(err.status) {
        res.status(err.status);
    } else {
        res.status(500);
    }
    res.render('error', { error : err });
    next(err);
};

app.use(errorHandler);

io.on('connection', function(socket){
    socket.on('chat message', function(msg){
    	console.log('message: ' + msg);
  	});
});

// logger that prevents circular object reference in javascript
var log = function(msg, obj) {
    console.log('\n');
    if(obj) {
        try {
            console.log(msg + JSON.stringify(obj));
        } catch(err) {
            var simpleObject = {};
            for (var prop in obj ){
                if (!obj.hasOwnProperty(prop)){
                    continue;
                }
                if (typeof(obj[prop]) == 'object'){
                    continue;
                }
                if (typeof(obj[prop]) == 'function'){
                    continue;
                }
                simpleObject[prop] = obj[prop];
            }
            console.log('circular-' + msg + JSON.stringify(simpleObject)); // returns cleaned up JSON
        }
    } else {
        console.log(msg);
    }
};

// secure web server
https.createServer(credentials, app).listen(3000);

// only redirect the home page. 403 forbid all others
http.createServer(function(req, res) {
    log('catch a redirect from ' + req.headers.host + ' (is HSTS working?)');
    log('redirect req = ', req);
    log('redirect res = ', res);
    if (req.headers.host + req.url === DOMAIN + '/') {
        res.writeHead(301, { 'Location' : 'https://' + req.headers.host + req.url });
        res.end();
    } else {
        res.writeHead(403);
        res.end();
    }
}).listen(8080);

log('ready to serve');<commit_msg>HTTPS Getting closer<commit_after>var fs 				= require('fs-extra');
var http 			= require('http'); // http protocol
var https 			= require('https'); // https protocol
var Mongo      		= require('mongodb').MongoClient;
var express 		= require('express'); // web server
var cookieParser 	= require('cookie-parser'); // parse cookies
var socketio 		= require('socket.io'); // websocket
var request 		= require('request'); // http trafficer
var bodyParser 		= require('body-parser'); // middleware
// Helmet

// web server
var app = express();
app.use(cookieParser());
var server = http.Server(app);
var io = socketio(server);

app.use('/', express.static('../Client/'));

var credentials = {
    key:  fs.readFileSync('bin/key.pem'),
    cert: fs.readFileSync('bin/cert.pem')
};

// body parsing ensures req.body property
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

// error handling middleware
var errorHandler = function(err, req, res, next) {
    if(err.status) {
        res.status(err.status);
    } else {
        res.status(500);
    }
    res.render('error', { error : err });
    next(err);
};

app.use(errorHandler);

io.on('connection', function(socket){
    socket.on('chat message', function(msg){
    	console.log('message: ' + msg);
  	});
});

// logger that prevents circular object reference in javascript
var log = function(msg, obj) {
    console.log('\n');
    if(obj) {
        try {
            console.log(msg + JSON.stringify(obj));
        } catch(err) {
            var simpleObject = {};
            for (var prop in obj ){
                if (!obj.hasOwnProperty(prop)){
                    continue;
                }
                if (typeof(obj[prop]) == 'object'){
                    continue;
                }
                if (typeof(obj[prop]) == 'function'){
                    continue;
                }
                simpleObject[prop] = obj[prop];
            }
            console.log('circular-' + msg + JSON.stringify(simpleObject)); // returns cleaned up JSON
        }
    } else {
        console.log(msg);
    }
};

// secure web server
https.createServer(credentials, app).listen(3000);

// only redirect the home page. 403 forbid all others
http.createServer(function(req, res) {
    log('catch a redirect from ' + req.headers.host + ' (is HSTS working?)');
    log('redirect req = ', req);
    log('redirect res = ', res);
    if (req.headers.host + req.url === DOMAIN + '/') {
        res.writeHead(301, { 'Location' : 'https://' + req.headers.host + req.url });
        res.end();
    } else {
        res.writeHead(403);
        res.end();
    }
}).listen(8080);

log('ready to serve');
<|endoftext|>


<commit_before>// SEE YOU IN 2017

const Promise = require('bluebird')
const promisify = Promise.promisify

const {join, resolve, basename} = require('path')

const log = require('npmlog')
const mkdirp = promisify(require('mkdirp'))
const mv = promisify(require('mv'))
const stat = promisify(require('fs').stat)

function place (albums, newRoot, groups) {
  return Promise.all(
    [...albums].map(album => {
      const albumPath = join(newRoot, album.toPath())
      const trackerGroup = groups.get(album.sourceArchive.path)
      return mkdirp(albumPath).then(() => {
        log.silly('place', 'created', albumPath)
        const tracker = trackerGroup.newItem(
          'moving tracks: ' + albumPath,
          album.tracks.length
        )

        return Promise.all(
          album.tracks.map(track => {
            const destination = resolve(
              newRoot,
              album.toPath(),
              track.safeName()
            )

            return stat(destination).then(() => {
              log.warn('place', destination, 'already exists; not overwriting')
              tracker.completeWork(1)
            }).catch((er) => {
              if (er.code !== 'ENOENT') throw er
              log.silly('place', 'moving', track.file.path, 'to', destination)
              return mv(track.file.path, destination).then(() => {
                track.file.path = destination
                tracker.completeWork(1)
              })
            })
          })
        )
      }).then(() => {
        const tracker = trackerGroup.newItem(
          'covers to ' + albumPath,
          album.pictures.length
        )

        return Promise.all(
          album.pictures.map(picture => {
            const destination = resolve(
              newRoot,
              album.toPath(),
              basename(picture.path)
            )

            return stat(destination).then(() => {
              log.warn('place', destination, 'already exists; not overwriting')
              tracker.completeWork(1)
            }).catch((er) => {
              if (er.code !== 'ENOENT') throw er
              return mv(picture.path, destination).then(() => {
                picture.path = destination
                tracker.completeWork(1)
              })
            })
          })
        )
      })
    })
  ).then(() => albums)
}

function moveToArchive (albums, root, groups) {
  return mkdirp(root).then(() => Promise.all(
    [...albums].map(album => {
      const archive = album.sourceArchive
      const trackerGroup = groups.get(archive)
      const tracker = trackerGroup.newItem('archiving: ' + archive, albums.size)
      const destination = join(root, basename(archive))
      if (!archive) {
        return Promise.reject(
          new Error(album.name + ' must have source archive path set.')
        )
      }
      log.verbose('moveToArchive', 'moving', archive, 'to', destination)
      return stat(destination).then(() => {
        log.warn('moveToArchive', destination, 'already exists; not overwriting')
        tracker.completeWork(1)
      }).catch((er) => {
        if (er.code !== 'ENOENT') throw er
        return mv(archive, destination).then(() => {
          album.destArchive = destination
          tracker.completeWork(1)
        })
      })
    })
  ))
}

module.exports = { place, moveToArchive }
<commit_msg>mover: ditch old require syntax<commit_after>// SEE YOU IN 2017

import fs from 'fs'

import { join, resolve, basename } from 'path'

import log from 'npmlog'
import mkdirpCB from 'mkdirp'
import mvCB from 'mv'
import { promisify } from 'bluebird'
import Promise from 'bluebird'

const mkdirp = promisify(mkdirpCB)
const mv = promisify(mvCB)
const stat = promisify(fs.stat)

export function place (albums, newRoot, groups) {
  return Promise.all(
    [...albums].map(album => {
      const albumPath = join(newRoot, album.toPath())
      const trackerGroup = groups.get(album.sourceArchive.path)
      return mkdirp(albumPath).then(() => {
        log.silly('place', 'created', albumPath)
        const tracker = trackerGroup.newItem(
          'moving tracks: ' + albumPath,
          album.tracks.length
        )

        return Promise.all(
          album.tracks.map(track => {
            const destination = resolve(
              newRoot,
              album.toPath(),
              track.safeName()
            )

            return stat(destination).then(() => {
              log.warn('place', destination, 'already exists; not overwriting')
              tracker.completeWork(1)
            }).catch((er) => {
              if (er.code !== 'ENOENT') throw er
              log.silly('place', 'moving', track.file.path, 'to', destination)
              return mv(track.file.path, destination).then(() => {
                track.file.path = destination
                tracker.completeWork(1)
              })
            })
          })
        )
      }).then(() => {
        const tracker = trackerGroup.newItem(
          'covers to ' + albumPath,
          album.pictures.length
        )

        return Promise.all(
          album.pictures.map(picture => {
            const destination = resolve(
              newRoot,
              album.toPath(),
              basename(picture.path)
            )

            return stat(destination).then(() => {
              log.warn('place', destination, 'already exists; not overwriting')
              tracker.completeWork(1)
            }).catch((er) => {
              if (er.code !== 'ENOENT') throw er
              return mv(picture.path, destination).then(() => {
                picture.path = destination
                tracker.completeWork(1)
              })
            })
          })
        )
      })
    })
  ).then(() => albums)
}

export function moveToArchive (albums, root, groups) {
  return mkdirp(root).then(() => Promise.all(
    [...albums].map(album => {
      const archive = album.sourceArchive
      const trackerGroup = groups.get(archive)
      const tracker = trackerGroup.newItem('archiving: ' + archive, albums.size)
      const destination = join(root, basename(archive))
      if (!archive) {
        return Promise.reject(
          new Error(album.name + ' must have source archive path set.')
        )
      }
      log.verbose('moveToArchive', 'moving', archive, 'to', destination)
      return stat(destination).then(() => {
        log.warn('moveToArchive', destination, 'already exists; not overwriting')
        tracker.completeWork(1)
      }).catch((er) => {
        if (er.code !== 'ENOENT') throw er
        return mv(archive, destination).then(() => {
          album.destArchive = destination
          tracker.completeWork(1)
        })
      })
    })
  ))
}
<|endoftext|>


<commit_before>/**
 *  Defines a Schema aware GraphIT client library
 */
import { queryBuilder } from "../gremlin";
import {
    find,
    findById,
    findOne,
    findCount,
    search,
    create,
    update,
    replace,
    connect,
    disconnect,
    deleteVertex,
    fetchMe
} from "./graph";
import { createVertex } from "../vertex/graph";
import { mapPromiseIfArray, deprecationWarning } from "../utils";
import {
    getRelationQuery,
    fetchVertices,
    fetchIds,
    fetchCount
} from "./relations";
import isPlainObject from "lodash.isplainobject";
import Schema from "../schema";
import Client from "hiro-graph-client";

//shorthand for creating the getCount/Ids/Vertices fetching functions
const relationFetch = (method, relations, options = {}) =>
    mapPromiseIfArray(vertex => vertex[method](relations, options));

const noEntity = "_no_entity";

/**
 *  The context is a wrapper for the schema and client.
 *
 *  The major expost of the entire module.
 *
 *  Apart from it's direct methods, every {@link Entity} in the {@link Schema} has a
 *  property on this object, which has the methods documented in {@link Context$Entity}.
 */
export default class Context {
    /**
     *  @param {Client|object} clientSpec - This should be an `hiro-graph-client` `Client` object,
     *                                              or the constructor args to create one.
     *  @param {Schema|Array} schemaSpec - This should be a {@link Schema} or the constructor args to create one.
     *  @param {?Map} [cache=new Map()] - The vertex cache. Any object satisfying the `Map` interface should be OK.
     */
    constructor(connectionSpec, schemaSpec, cache = new Map()) {
        let client = connectionSpec;
        if (isPlainObject(connectionSpec)) {
            client = new Client(connectionSpec);
        }

        let schema = schemaSpec;
        if (Array.isArray(schemaSpec)) {
            schema = new Schema(schemaSpec);
        }

        this._client = client;
        this._schema = schema;
        this._cache = cache;
        this._log = [];

        //this adds the instance specific methods for each entity type
        //and one for "_no_entity"
        mapEntityShortcuts(this, [noEntity].concat(schema.names));
    }

    /**
     *  This returns the vertex from the owner of the access token in use.
     *  @return {Promise<GraphVertex>}
     */
    me() {
        //this is a bit different.
        return fetchMe(this);
    }

    /**
     * Get's the underlying GraphIT Client.
     *
     * @return {Client}
     */
    getClient() {
        return this._client;
    }

    /**
     *  The old method for getting a connection, deprecated
     *  @deprecated
     */
    getConnection() {
        return deprecationWarning(
            () => this.getClient(),
            "`getConnection` is deprecated, please use `getClient` instead. This method will be removed in a future version"
        );
    }

    /**
     * Exchange the current cache for a new one.
     *
     * You likely want to do this early on, before
     * any entries have gone in.
     *
     * @param {Map} cache - the new cache to use. Only needs to satisfy the `Map` interface, not actually be a `Map`
     */
    setCache(cache) {
        this._cache = cache;
    }

    /**
     *  On the Context itself, this is an `un-typed` query for a single vertex.
     *
     *  i.e. will search all entity types and return any one of them.
     *
     *  @param {LuceneQuery} query - the lucene query to perform
     *  @param {object} options - the options to pass on to the query {@todo document these}
     *  @return {Promise<GraphVertex>} - the first vertex found or an error
     */
    findOne(query, options = {}) {
        return this._no_entity.findOne(query, options);
    }
    /**
     *  On the Context itself, this is an `un-typed` query by id only
     *
     *  i.e. will search all entity types for the given id or array of ids.
     *
     *  @param {string|Array<string>} idOrIds - the id or array of ids to fetch
     *  @param {object} options - the options to pass on to the query {@todo document these}
     *  @return {Promise<OneOrMoreVertices>} - the vertex/vertices found or an error
     */
    findById(idOrIds, options = {}) {
        return this._no_entity.findById(idOrIds, options);
    }

    /**
     *  On the Context itself, this is an `un-typed` query.
     *
     *  i.e. will search all entity types and return any of them.
     *
     *  @param {LuceneQuery} query - the lucene query to perform
     *  @param {object} options - the options to pass on to the query {@todo document these}
     *  @return {Promise<OneOrMoreVertices>} - the first vertex found or an error
     */
    find(query, options = {}) {
        return this._no_entity.find(query, options);
    }

    /**
     *  On the Context itself, this is an `un-typed` query.
     *
     *  i.e. will search all entity types and return the count of results
     *
     *  @param {LuceneQuery} query - the lucene query to perform
     *  @param {object} options - the options to pass on to the query {@todo document these}
     *  @return {Promise<number>} - the count of results or an error
     */
    findCount(query, options = {}) {
        return this._no_entity.findCount(query, options);
    }
    /**
     *  On the Context itself, this is an `un-typed` search.
     *
     *  i.e. will search all entity types and return any of them.
     *
     *  @param {string|object} query - the search term or search definition.
     *  @param {LuceneQuery} filter - the lucene query to further restrict the results
     *  @param {object} options - the options to pass on to the query {@todo document these}
     *  @return {Promise<OneOrMoreVertices>} - the first vertex found or an error
     */
    search(query, filter = {}, options = {}) {
        return this._no_entity.search(query, options);
    }

    /**
     *  Deletes a vertex by id.
     *
     *  @param {string} vertexId - the id of the vertex to delete
     *  @param {object} options - the options to pass on to the query {@todo document these}
     *  @return {Promise<GraphVertex>} - the vertex (marked as deleted)
     */
    delete(vertexId, options = {}) {
        return deleteVertex(this, vertexId, options);
    }

    /**
     *  Create A Gremlin Query Builder with Context.
     *
     *  @param {?string} initialQuery - the starting point for the new query.
     *  @return {GremlinQueryBuilder} - a context aware gremlin query builder (e.g. `query.execute()` will work)
     */
    gremlin(initialQuery) {
        return queryBuilder(initialQuery, this);
    }

    /**
     *  Passthrough a count fetch in a promise
     *
     *  @example
     *  context.find({}).then(context.fetchCount(["related"]));
     *
     *  @param {Array<string>} relations - the relations to query for. These should match valid relation names on the entities passed in.
     *  @param {object} options - options to pass through to the underlying call
     *  @return {function(items: OneOrMoreVertices): Promise<OneOrMoreVertices>}
     *      - returns a function which will call `fetchCount(relations, options)` on each input
     */
    fetchCount(relations, options = {}) {
        return relationFetch("fetchCount", relations, options);
    }

    /**
     *  Passthrough a id fetch in a promise
     *
     *  @example
     *  context.find({}).then(context.fetchIds(["related"]));
     *
     *  @param {Array<string>} relations - the relations to query for. These should match valid relation names on the entities passed in.
     *  @param {object} options - options to pass through to the underlying call
     *  @return {function(items: OneOrMoreVertices): Promise<OneOrMoreVertices>}
     *      - returns a function which will call `fetchIds(relations, options)` on each input
     */
    fetchIds(relations, options = {}) {
        return relationFetch("fetchIds", relations, options);
    }

    /**
     *  Passthrough a vertex fetch in a promise
     *
     *  @example
     *  context.find({}).then(context.fetchVertices(["related"]));
     *
     *  @param {Array<string>} relations - the relations to query for. These should match valid relation names on the entities passed in.
     *  @param {object} options - options to pass through to the underlying call
     *  @return {function(items: OneOrMoreVertices): Promise<OneOrMoreVertices>}
     *      - returns a function which will call `fetchVertices(relations, options)` on each input
     */
    fetchVertices(relations, options = {}) {
        return relationFetch("fetchVertices", relations, options);
    }

    /**
     *  Fetch an entity from the schema.
     *
     *  @param {string} name - the name of the entity, can be the application name, or the OGIT name
     *  @return {?Entity} - the entity if found.
     */
    getEntity(name) {
        return this._schema.get(name);
    }

    /**
     *  Manually remove an item from the ORM cache.
     *
     *  @param {string} vertexId - the ID of the vertex to drop.
     *  @return {undefined} - no return value
     */
    remove(vertexId) {
        this.cache.delete(vertexId);
    }

    /**
     *  Manually give the orm data, raw from Graphit
     *
     *  Useful when you have have to bypass the regular system, or have nodes stored somewhere else.
     *
     *  @param {object} rawData - the raw GraphIT vertex data;
     *  @return {GraphVertex} - the inserted vertex
     */
    insertRaw(rawData) {
        const entity = this.getEntity(rawData["ogit/_type"]);
        const decoded = entity.decode(rawData);
        return this.insert(decoded);
    }

    /**
     *  Manually give the orm data, in application format
     *
     *  @param {object} appData - the application vertex data object
     *  @return {GraphVertex} - the inserted vertex
     */
    insert(appData) {
        return createVertex(appData, this);
    }
}

const mixinMethods = {
    find: (ctx, entity) => (query, options = {}) =>
        find(ctx, entity, query, options),
    findById: (ctx, entity) => (idOrIds, options = {}) =>
        findById(ctx, entity, idOrIds, options),
    findOne: (ctx, entity) => (query, options = {}) =>
        findOne(ctx, entity, query, options),
    findCount: (ctx, entity) => (query, options = {}) =>
        findCount(ctx, entity, query, options),
    search: (ctx, entity) => (query, filter, options = {}) =>
        search(ctx, entity, query, options),
    create: (ctx, entity) => (data, options = {}) =>
        create(ctx, entity, data, options),
    connect: (ctx, entity) => (relation, source, target, options = {}) =>
        connect(ctx, entity, { relation, source, target }, options),
    disconnect: (ctx, entity) => (relation, source, target, options = {}) =>
        disconnect(ctx, entity, { relation, source, target }, options),
    update: (ctx, entity) => (vertexId, appData, options = {}) =>
        update(ctx, entity, vertexId, appData, options),
    replace: (ctx, entity) => (vertexId, appData, options = {}) =>
        replace(ctx, entity, vertexId, appData, options),
    encode: (ctx, entity) => appData => entity.encode(appData),
    decode: (ctx, entity) => graphData => entity.decode(graphData),
    relationQuery: (ctx, entity) => relation =>
        getRelationQuery(entity, relation),
    findRelationVertices: (ctx, entity) => (id, relations) =>
        fetchVertices(ctx, entity)(relations)(id),
    findRelationIds: (ctx, entity) => (id, relations) =>
        fetchIds(ctx, entity)(relations)(id),
    findRelationCount: (ctx, entity) => (id, relations) =>
        fetchCount(ctx, entity)(relations)(id),
    hasRelation: (ctx, entity) => (id, relation, test) =>
        getRelationQuery(entity, relation)
            .has("ogit/_id", test)
            .count()
            .executeInContext(ctx, id, { raw: true })
            .then(([count]) => count > 0),
    fetchVertices,
    fetchIds,
    fetchCount
};
const mixinMethodNames = Object.keys(mixinMethods);

//Adds entity methods
//
// like ctx.Profile.find()
const mapEntityShortcuts = (ctx, names) => {
    //we add "_unbound" to add use for the unbound instance methods.
    //they have a null entity, the others get an Identity
    names.forEach(name => {
        const entity = ctx._schema.get(name === noEntity ? null : name);
        ctx[name] = mixinMethodNames.reduce((obj, method) => {
            obj[method] = mixinMethods[method](ctx, entity);
            return obj;
        }, {});
    });
};
<commit_msg>Add helpful error if fetching relations on plain<commit_after>/**
 *  Defines a Schema aware GraphIT client library
 */
import { queryBuilder } from "../gremlin";
import {
    find,
    findById,
    findOne,
    findCount,
    search,
    create,
    update,
    replace,
    connect,
    disconnect,
    deleteVertex,
    fetchMe
} from "./graph";
import { createVertex } from "../vertex/graph";
import { mapPromiseIfArray, deprecationWarning } from "../utils";
import {
    getRelationQuery,
    fetchVertices,
    fetchIds,
    fetchCount
} from "./relations";
import isPlainObject from "lodash.isplainobject";
import Schema from "../schema";
import Client from "hiro-graph-client";

//shorthand for creating the getCount/Ids/Vertices fetching functions
const relationFetch = (method, relations, options = {}) =>
    mapPromiseIfArray(vertex => {
        if (typeof vertex[method] !== "function") {
            throw new TypeError(
                `Trying to call "${method}" on non GraphVertex object!\n` +
                    `Check whether or not you have converted the objects to plain`
            );
        }
        return vertex[method](relations, options);
    });

const noEntity = "_no_entity";

/**
 *  The context is a wrapper for the schema and client.
 *
 *  The major expost of the entire module.
 *
 *  Apart from it's direct methods, every {@link Entity} in the {@link Schema} has a
 *  property on this object, which has the methods documented in {@link Context$Entity}.
 */
export default class Context {
    /**
     *  @param {Client|object} clientSpec - This should be an `hiro-graph-client` `Client` object,
     *                                              or the constructor args to create one.
     *  @param {Schema|Array} schemaSpec - This should be a {@link Schema} or the constructor args to create one.
     *  @param {?Map} [cache=new Map()] - The vertex cache. Any object satisfying the `Map` interface should be OK.
     */
    constructor(connectionSpec, schemaSpec, cache = new Map()) {
        let client = connectionSpec;
        if (isPlainObject(connectionSpec)) {
            client = new Client(connectionSpec);
        }

        let schema = schemaSpec;
        if (Array.isArray(schemaSpec)) {
            schema = new Schema(schemaSpec);
        }

        this._client = client;
        this._schema = schema;
        this._cache = cache;
        this._log = [];

        //this adds the instance specific methods for each entity type
        //and one for "_no_entity"
        mapEntityShortcuts(this, [noEntity].concat(schema.names));
    }

    /**
     *  This returns the vertex from the owner of the access token in use.
     *  @return {Promise<GraphVertex>}
     */
    me() {
        //this is a bit different.
        return fetchMe(this);
    }

    /**
     * Get's the underlying GraphIT Client.
     *
     * @return {Client}
     */
    getClient() {
        return this._client;
    }

    /**
     *  The old method for getting a connection, deprecated
     *  @deprecated
     */
    getConnection() {
        return deprecationWarning(
            () => this.getClient(),
            "`getConnection` is deprecated, please use `getClient` instead. This method will be removed in a future version"
        );
    }

    /**
     * Exchange the current cache for a new one.
     *
     * You likely want to do this early on, before
     * any entries have gone in.
     *
     * @param {Map} cache - the new cache to use. Only needs to satisfy the `Map` interface, not actually be a `Map`
     */
    setCache(cache) {
        this._cache = cache;
    }

    /**
     *  On the Context itself, this is an `un-typed` query for a single vertex.
     *
     *  i.e. will search all entity types and return any one of them.
     *
     *  @param {LuceneQuery} query - the lucene query to perform
     *  @param {object} options - the options to pass on to the query {@todo document these}
     *  @return {Promise<GraphVertex>} - the first vertex found or an error
     */
    findOne(query, options = {}) {
        return this._no_entity.findOne(query, options);
    }
    /**
     *  On the Context itself, this is an `un-typed` query by id only
     *
     *  i.e. will search all entity types for the given id or array of ids.
     *
     *  @param {string|Array<string>} idOrIds - the id or array of ids to fetch
     *  @param {object} options - the options to pass on to the query {@todo document these}
     *  @return {Promise<OneOrMoreVertices>} - the vertex/vertices found or an error
     */
    findById(idOrIds, options = {}) {
        return this._no_entity.findById(idOrIds, options);
    }

    /**
     *  On the Context itself, this is an `un-typed` query.
     *
     *  i.e. will search all entity types and return any of them.
     *
     *  @param {LuceneQuery} query - the lucene query to perform
     *  @param {object} options - the options to pass on to the query {@todo document these}
     *  @return {Promise<OneOrMoreVertices>} - the first vertex found or an error
     */
    find(query, options = {}) {
        return this._no_entity.find(query, options);
    }

    /**
     *  On the Context itself, this is an `un-typed` query.
     *
     *  i.e. will search all entity types and return the count of results
     *
     *  @param {LuceneQuery} query - the lucene query to perform
     *  @param {object} options - the options to pass on to the query {@todo document these}
     *  @return {Promise<number>} - the count of results or an error
     */
    findCount(query, options = {}) {
        return this._no_entity.findCount(query, options);
    }
    /**
     *  On the Context itself, this is an `un-typed` search.
     *
     *  i.e. will search all entity types and return any of them.
     *
     *  @param {string|object} query - the search term or search definition.
     *  @param {LuceneQuery} filter - the lucene query to further restrict the results
     *  @param {object} options - the options to pass on to the query {@todo document these}
     *  @return {Promise<OneOrMoreVertices>} - the first vertex found or an error
     */
    search(query, filter = {}, options = {}) {
        return this._no_entity.search(query, options);
    }

    /**
     *  Deletes a vertex by id.
     *
     *  @param {string} vertexId - the id of the vertex to delete
     *  @param {object} options - the options to pass on to the query {@todo document these}
     *  @return {Promise<GraphVertex>} - the vertex (marked as deleted)
     */
    delete(vertexId, options = {}) {
        return deleteVertex(this, vertexId, options);
    }

    /**
     *  Create A Gremlin Query Builder with Context.
     *
     *  @param {?string} initialQuery - the starting point for the new query.
     *  @return {GremlinQueryBuilder} - a context aware gremlin query builder (e.g. `query.execute()` will work)
     */
    gremlin(initialQuery) {
        return queryBuilder(initialQuery, this);
    }

    /**
     *  Passthrough a count fetch in a promise
     *
     *  @example
     *  context.find({}).then(context.fetchCount(["related"]));
     *
     *  @param {Array<string>} relations - the relations to query for. These should match valid relation names on the entities passed in.
     *  @param {object} options - options to pass through to the underlying call
     *  @return {function(items: OneOrMoreVertices): Promise<OneOrMoreVertices>}
     *      - returns a function which will call `fetchCount(relations, options)` on each input
     */
    fetchCount(relations, options = {}) {
        return relationFetch("fetchCount", relations, options);
    }

    /**
     *  Passthrough a id fetch in a promise
     *
     *  @example
     *  context.find({}).then(context.fetchIds(["related"]));
     *
     *  @param {Array<string>} relations - the relations to query for. These should match valid relation names on the entities passed in.
     *  @param {object} options - options to pass through to the underlying call
     *  @return {function(items: OneOrMoreVertices): Promise<OneOrMoreVertices>}
     *      - returns a function which will call `fetchIds(relations, options)` on each input
     */
    fetchIds(relations, options = {}) {
        return relationFetch("fetchIds", relations, options);
    }

    /**
     *  Passthrough a vertex fetch in a promise
     *
     *  @example
     *  context.find({}).then(context.fetchVertices(["related"]));
     *
     *  @param {Array<string>} relations - the relations to query for. These should match valid relation names on the entities passed in.
     *  @param {object} options - options to pass through to the underlying call
     *  @return {function(items: OneOrMoreVertices): Promise<OneOrMoreVertices>}
     *      - returns a function which will call `fetchVertices(relations, options)` on each input
     */
    fetchVertices(relations, options = {}) {
        return relationFetch("fetchVertices", relations, options);
    }

    /**
     *  Fetch an entity from the schema.
     *
     *  @param {string} name - the name of the entity, can be the application name, or the OGIT name
     *  @return {?Entity} - the entity if found.
     */
    getEntity(name) {
        return this._schema.get(name);
    }

    /**
     *  Manually remove an item from the ORM cache.
     *
     *  @param {string} vertexId - the ID of the vertex to drop.
     *  @return {undefined} - no return value
     */
    remove(vertexId) {
        this.cache.delete(vertexId);
    }

    /**
     *  Manually give the orm data, raw from Graphit
     *
     *  Useful when you have have to bypass the regular system, or have nodes stored somewhere else.
     *
     *  @param {object} rawData - the raw GraphIT vertex data;
     *  @return {GraphVertex} - the inserted vertex
     */
    insertRaw(rawData) {
        const entity = this.getEntity(rawData["ogit/_type"]);
        const decoded = entity.decode(rawData);
        return this.insert(decoded);
    }

    /**
     *  Manually give the orm data, in application format
     *
     *  @param {object} appData - the application vertex data object
     *  @return {GraphVertex} - the inserted vertex
     */
    insert(appData) {
        return createVertex(appData, this);
    }
}

const mixinMethods = {
    find: (ctx, entity) => (query, options = {}) =>
        find(ctx, entity, query, options),
    findById: (ctx, entity) => (idOrIds, options = {}) =>
        findById(ctx, entity, idOrIds, options),
    findOne: (ctx, entity) => (query, options = {}) =>
        findOne(ctx, entity, query, options),
    findCount: (ctx, entity) => (query, options = {}) =>
        findCount(ctx, entity, query, options),
    search: (ctx, entity) => (query, filter, options = {}) =>
        search(ctx, entity, query, options),
    create: (ctx, entity) => (data, options = {}) =>
        create(ctx, entity, data, options),
    connect: (ctx, entity) => (relation, source, target, options = {}) =>
        connect(ctx, entity, { relation, source, target }, options),
    disconnect: (ctx, entity) => (relation, source, target, options = {}) =>
        disconnect(ctx, entity, { relation, source, target }, options),
    update: (ctx, entity) => (vertexId, appData, options = {}) =>
        update(ctx, entity, vertexId, appData, options),
    replace: (ctx, entity) => (vertexId, appData, options = {}) =>
        replace(ctx, entity, vertexId, appData, options),
    encode: (ctx, entity) => appData => entity.encode(appData),
    decode: (ctx, entity) => graphData => entity.decode(graphData),
    relationQuery: (ctx, entity) => relation =>
        getRelationQuery(entity, relation),
    findRelationVertices: (ctx, entity) => (id, relations) =>
        fetchVertices(ctx, entity)(relations)(id),
    findRelationIds: (ctx, entity) => (id, relations) =>
        fetchIds(ctx, entity)(relations)(id),
    findRelationCount: (ctx, entity) => (id, relations) =>
        fetchCount(ctx, entity)(relations)(id),
    hasRelation: (ctx, entity) => (id, relation, test) =>
        getRelationQuery(entity, relation)
            .has("ogit/_id", test)
            .count()
            .executeInContext(ctx, id, { raw: true })
            .then(([count]) => count > 0),
    fetchVertices,
    fetchIds,
    fetchCount
};
const mixinMethodNames = Object.keys(mixinMethods);

//Adds entity methods
//
// like ctx.Profile.find()
const mapEntityShortcuts = (ctx, names) => {
    //we add "_unbound" to add use for the unbound instance methods.
    //they have a null entity, the others get an Identity
    names.forEach(name => {
        const entity = ctx._schema.get(name === noEntity ? null : name);
        ctx[name] = mixinMethodNames.reduce((obj, method) => {
            obj[method] = mixinMethods[method](ctx, entity);
            return obj;
        }, {});
    });
};
<|endoftext|>


<commit_before>module.exports = {

    publicPathPrefix: '__koot_webpack_dev_server__',
    entryClientHMR: 'webpack-dev-server-client',

    hmrOptions: {
        multiStep: true,
        fullBuildTimeout: 0.5 * 1000,
        requestTimeout: 5 * 60 * 1000
    },

}
<commit_msg>koot/dev: update hmr options<commit_after>module.exports = {

    publicPathPrefix: '__koot_webpack_dev_server__',
    entryClientHMR: 'webpack-dev-server-client',

    hmrOptions: {
        multiStep: true,
        // fullBuildTimeout: 0.5 * 1000,
        // requestTimeout: 5 * 60 * 1000
    },

}
<|endoftext|>


<commit_before>var fs = require("fs");
var jsonpack = require('jsonpack')
var LineByLineReader = require('line-by-line')
var Lock = require('rwlock');

var StorageModule = function (silent) {
	this.storageFilePath = null;
	this.indexFilePath = null;
	this.map = {};
	this.dataPosition = 0;

	this.indexLock = new Lock();
	this.dataLock = new Lock();
	this.silent = silent;
};

StorageModule.prototype.init = function(fw, onFinished) {
    this.fw = fw;

    if(typeof(fw.config.StorageFile) === "string"){
    	this.storageFilePath = fw.config.StorageFile;
    } else {
    	if(this.silent !== true)
    		console.log("[StorageModule] StorageFile not specified in configuration, so using ../storage.data");
    	this.storageFilePath = "../storage.data";
    }

    this.indexFilePath = this.storageFilePath + ".index";

    if(!fs.existsSync(this.storageFilePath))
    	fs.openSync(this.storageFilePath, 'w')
    if(!fs.existsSync(this.indexFilePath))
    	fs.openSync(this.indexFilePath, 'w')

    var t = this;
	fs.stat(t.storageFilePath, function (err, stats) {
		t.dataPosition = stats.size;

		var lr = new LineByLineReader(t.indexFilePath);
		lr.on('line', function (line) {
			var l = line.split(";");
		    t.map[l[0]] = {p: parseInt(l[1]), l: parseInt(l[2])};
		});

		lr.on('end', function () {
			if(t.silent !== true)
				console.log("[StorageModule] Data loaded")
		    onFinished.call(t);
		});
	});
}

StorageModule.prototype.onMessage = function (req, callback) {
	if(typeof(req.body.key) !== "string"){
		callback({error: "Invalid request"});
		return;
	}
}

StorageModule.prototype.get = function(key, callback){
	if(key in this.map){
		var buffer = new Buffer(parseInt(this.map[key].l));
		var t = this;

		this.dataLock.readLock(function (release) {
			fs.open(t.storageFilePath, 'r', '0666', function(err, fd){
				fs.read(fd, buffer, 0, t.map[key].l, t.map[key].p, function(err, len, data){
					fs.close(fd, function(){release();})

					var s = new Buffer(data.toString('ascii'), 'base64').toString('ascii')
					s = jsonpack.unpack(s);
					//console.log(s);
					//s = JSON.parse(s);
					callback.call(t, null, s);
				})
			})
		});
	}
	else {
		callback.call(this, null, {});
	}
}

StorageModule.prototype.getMultiple = function(keys, callback){
	var res = [];
	var numHandled = 0;

	if(keys.length <= 0){
		callback(null, []);
		return;
	}

	function getNext(){
		if(numHandled >= keys.length){
			callback(null, res);
			return;
		}

		this.get(keys[numHandled], function(err, data){
			numHandled++;
			res.push(data);
			getNext.call(this);
		})
	}
	getNext.call(this);
}

StorageModule.prototype.setMultiple = function(keysAndValues, callback){

	if(typeof keysAndValues !== "object"){
		callback("Need an object");
		return;
	}

	var handled = 0;
	var num = 0;
	for(i in keysAndValues)
		num++;

	for(i in keysAndValues){
		this.set(i, keysAndValues[i], function(err, data){
			handled += 1;

			if(handled >= num)
				callback(null, handled);
		})
	}
}

StorageModule.prototype.set = function(key, value, callback){
	if(typeof callback !== "function")
		callback = function(){};

	if(typeof key !== "string"){
		callback("No key specified", value);
		return;
	}

	key = key.replace(/(\r\n|\n|\r|;)/gm,"");

	if(key.length < 1){
		callback("No key specified", value);
		return;
	}

	if(typeof value !== "object"){
		callback("Invalid value for set", value);
		return;
	}

	var valueToStore = new Buffer(jsonpack.pack(JSON.stringify(value ? value : {}))).toString('base64');

	var t = this;
	//console.log(key + " beginning set")
	this.dataLock.writeLock(function (release) {
		//console.log(key + " got write lock")
		fs.appendFile(t.storageFilePath, valueToStore, function(err){
			t.dataPosition += valueToStore.length;
			//console.log(key + " data file appended")

			release();

			t.indexLock.writeLock(function (release) {
				//console.log(key + " got index lock")

				var idx = t.dataPosition - valueToStore.length;
				fs.appendFile(t.indexFilePath, key + ";" + idx + ";" + valueToStore.length + "\n", function(err){
					//console.log(key + " index file appended")

					t.map[key] = {p: idx, l: valueToStore.length};
					//console.log(t.map);
					release();
					callback(null, value);
				});
			})
		});
	});
}

module.exports = StorageModule;<commit_msg>Client requests<commit_after>var fs = require("fs");
var jsonpack = require('jsonpack')
var LineByLineReader = require('line-by-line')
var Lock = require('rwlock');

var StorageModule = function (silent) {
	this.storageFilePath = null;
	this.indexFilePath = null;
	this.map = {};
	this.dataPosition = 0;

	this.indexLock = new Lock();
	this.dataLock = new Lock();
	this.silent = silent;
};

StorageModule.prototype.init = function(fw, onFinished) {
    this.fw = fw;

    if(typeof(fw.config.StorageFile) === "string"){
    	this.storageFilePath = fw.config.StorageFile;
    } else {
    	if(this.silent !== true)
    		console.log("[StorageModule] StorageFile not specified in configuration, so using ../storage.data");
    	this.storageFilePath = "../storage.data";
    }

    this.indexFilePath = this.storageFilePath + ".index";

    if(!fs.existsSync(this.storageFilePath))
    	fs.openSync(this.storageFilePath, 'w')
    if(!fs.existsSync(this.indexFilePath))
    	fs.openSync(this.indexFilePath, 'w')

    var t = this;
	fs.stat(t.storageFilePath, function (err, stats) {
		t.dataPosition = stats.size;

		var lr = new LineByLineReader(t.indexFilePath);
		lr.on('line', function (line) {
			var l = line.split(";");
		    t.map[l[0]] = {p: parseInt(l[1]), l: parseInt(l[2])};
		});

		lr.on('end', function () {
			if(t.silent !== true)
				console.log("[StorageModule] Data loaded")
		    onFinished.call(t);
		});
	});
}

StorageModule.prototype.onMessage = function (req, callback) {
	if(typeof(req.body.key) !== "string"){
		callback({error: "Invalid request"});
		return;
	}

	this.get(req.body.key, function(err, val){
		if(val.allowClient == true)
			callback(val);
		else
			callback({error: "Not allowed from client"});
	})
}

StorageModule.prototype.get = function(key, callback){
	if(key in this.map){
		var buffer = new Buffer(parseInt(this.map[key].l));
		var t = this;

		this.dataLock.readLock(function (release) {
			fs.open(t.storageFilePath, 'r', '0666', function(err, fd){
				fs.read(fd, buffer, 0, t.map[key].l, t.map[key].p, function(err, len, data){
					fs.close(fd, function(){release();})

					var s = new Buffer(data.toString('ascii'), 'base64').toString('ascii')
					s = jsonpack.unpack(s);
					//console.log(s);
					//s = JSON.parse(s);
					callback.call(t, null, s);
				})
			})
		});
	}
	else {
		callback.call(this, null, {});
	}
}

StorageModule.prototype.getMultiple = function(keys, callback){
	var res = [];
	var numHandled = 0;

	if(keys.length <= 0){
		callback(null, []);
		return;
	}

	function getNext(){
		if(numHandled >= keys.length){
			callback(null, res);
			return;
		}

		this.get(keys[numHandled], function(err, data){
			numHandled++;
			res.push(data);
			getNext.call(this);
		})
	}
	getNext.call(this);
}

StorageModule.prototype.setMultiple = function(keysAndValues, callback){

	if(typeof keysAndValues !== "object"){
		callback("Need an object");
		return;
	}

	var handled = 0;
	var num = 0;
	for(i in keysAndValues)
		num++;

	for(i in keysAndValues){
		this.set(i, keysAndValues[i], function(err, data){
			handled += 1;

			if(handled >= num)
				callback(null, handled);
		})
	}
}

StorageModule.prototype.set = function(key, value, callback){
	if(typeof callback !== "function")
		callback = function(){};

	if(typeof key !== "string"){
		callback("No key specified", value);
		return;
	}

	key = key.replace(/(\r\n|\n|\r|;)/gm,"");

	if(key.length < 1){
		callback("No key specified", value);
		return;
	}

	if(typeof value !== "object"){
		callback("Invalid value for set", value);
		return;
	}

	var valueToStore = new Buffer(jsonpack.pack(JSON.stringify(value ? value : {}))).toString('base64');

	var t = this;
	//console.log(key + " beginning set")
	this.dataLock.writeLock(function (release) {
		//console.log(key + " got write lock")
		fs.appendFile(t.storageFilePath, valueToStore, function(err){
			t.dataPosition += valueToStore.length;
			//console.log(key + " data file appended")

			release();

			t.indexLock.writeLock(function (release) {
				//console.log(key + " got index lock")

				var idx = t.dataPosition - valueToStore.length;
				fs.appendFile(t.indexFilePath, key + ";" + idx + ";" + valueToStore.length + "\n", function(err){
					//console.log(key + " index file appended")

					t.map[key] = {p: idx, l: valueToStore.length};
					//console.log(t.map);
					release();
					callback(null, value);
				});
			})
		});
	});
}

module.exports = StorageModule;<|endoftext|>