<commit_before>//Drop Model
SoapStone.Drop = function (args) {
  if (args) {
    this.setAttributes(args);
  }
};

SoapStone.Drop.prototype.setAttributes = function (args) {
  this.id = args.id;
  if (args.coords) {
    this.coords = {};
    this.coords.longitude = args.coords.longitude;
    this.coords.latitude = args.coords.latitude;
  }
  if (args.lon && args.lat) {
    this.coords = {};
    this.coords.latitude = args.lat;
    this.coords.longitude = args.lon;
  }
  if (this.coords) {
    this.lat = this.coords.latitude;
    this.lon = this.coords.longitude;
  }
  this.text = args.text;
  this.photo = args.photo;
  this.distance = args.distance;
  this.has_photo = args["has_photo?"];
  this.created_at = args.created_at;
  this.snaps_count = args.snaps_count;
  this.comments_count = args.comments_count;
  this.snapped_by_you = args["snapped_by?"];
  if (args.user) {
    this.user = new SoapStone.User(args.user);
  }
  if (args.comments) {
    this.comments = args.comments.map(function (data) {
      return new SoapStone.Comment(data);
    });
  }
};

SoapStone.Drop.prototype.save = function (formData) {
  formData.append('drop[lat]', this.lat);
  formData.append('drop[lon]', this.lon);
  return $.ajax({
    type: "POST",
    url:  "/drops",
    cache: false,
    contentType: false,
    processData: false,
    data: formData
  });
};

SoapStone.Drop.prototype.find = function (id) {
  var self = this;
  return new Promise(function (resolve, reject) {
    $.ajax({
      type: "GET",
      url: "/drops/" + id,
      dataType: 'json'
     })
    .then(function (response) {
      self.setAttributes(response);
      resolve(self);
    })
    .fail(function () {
      reject();
    });
  });
};

SoapStone.Drop.prototype.addSnap = function () {
  var self = this;
  return $.ajax({
    type:"POST",
    url: "/drops/" + self.id + "/snaps"
  }).then(function () {
    self.snaps_count +=1;
    self.snapped_by_you = true;
  });
};

SoapStone.Drop.prototype.createComment = function (comment) {
  var self = this;
  return $.ajax({
    type:"POST",
    url: "/drops/" + self.id + "/comments",
    data:{comment: $("[data-form='comment-form']").val()}
  }).then(function (response) {
    self.comments.push(new SoapStone.Comment(response));
    self.comments_count += 1;
  });
};

SoapStone.Comment = function (args) {
  this.text = args.text;
  if (args.user) {
    this.user = {};
    this.user.id = args.user.id;
    this.user.username = args.user.username;
    this.user.avatar = args.user.avatar;
  }
};

// View
SoapStone.DropView = function () {
  this.showTemplate = Handlebars.compile($("[data-template='show-drop']").html());
  this.dropListTemplate = Handlebars.compile($("[data-template='drop-list']").html());
  Handlebars.registerPartial("snap-button", $("[data-partial='snap-button-partial']").html());
  this.snapButtonTemplate = Handlebars.compile($("[data-partial='snap-button-partial']").html());
  Handlebars.registerPartial("comment", $("[data-partial='comment-partial']").html());
  this.commentsTemplate = Handlebars.compile($("[data-partial='comment-partial']").html());
  this.setUpEventHandlers();
};

SoapStone.DropView.prototype.setUpEventHandlers = function () {
  var self = this;

  $("[data-role='drop-form']").on('submit', function (event) {
    event.preventDefault();
    self.controller.createDrop($("[data-role='drop-form']"));
  });

  $("[data-button='friend-filter']").on('click', function (e) {
    self.controller.loadDrops("/followees");
  });

  $("[data-button='public-filter']").on('click', function (e) {
    self.controller.loadDrops();
  });

  $("[data-button='new-button']").on('click', function (event) {
    event.preventDefault();
    self.showNewDropForm();
  });

  $("[data-button='close-form']").on('click', function (event) {
    event.preventDefault();
    self.hideNewDropForm();
  });
};

SoapStone.DropView.prototype.showNewDropForm = function () {
  $("[data-view='new-form']").show();
};

SoapStone.DropView.prototype.hideNewDropForm = function () {
  $("[data-view='new-form']").removeClass('uploading');
  $("[data-view='new-form']").hide();
};

SoapStone.DropView.prototype.showUploadIndicator = function () {
  $("[data-view='new-form']").addClass('uploading');
};

SoapStone.DropView.prototype.showUploadSuccess = function (response) {
  console.log("Drop posted successfuly!");
  toastr.success("Drop Posted", "Success");
  this.hideNewDropForm();
};

SoapStone.DropView.prototype.showUploadFailure = function (response) {
  console.log("Drop failed to post.");
  toastr.error("Drop failed to post.", "Error");
  this.hideNewDropForm();
};

SoapStone.DropView.prototype.updateSnapButton = function (drop) {
  $("[data-button='snap-button']").replaceWith(this.snapButtonTemplate(drop));
};

SoapStone.DropView.prototype.updateComments = function (drop) {
  $(".comment-list").replaceWith(this.commentsTemplate(drop));
};

SoapStone.DropView.prototype.showDrop = function (drop) {
  var self = this;
  $('body').append(this.showTemplate(drop));
  $("[data-view='map']").hide();
  $("[data-menu='map']").hide();
  $("[data-button='close-drop']").on('click', function (event) {
    self.closeDrop();
  });

  $("[data-button='snap-button']").on('click', function (event) {
    event.preventDefault();
    self.controller.addSnap(drop);
  });

  $("[data-button='comment-button']").on('click', function (event){
    event.preventDefault();
    self.controller.createComment(drop);
    $("[data-form='comment-form']").val('');
  });
};

SoapStone.DropView.prototype.clearDropList = function (drop) {
  $(".drop-list").remove();
};

SoapStone.DropView.prototype.getMarker = function (drops, id) {
  for (var i = 0; i < drops.length; i++) {
    var drop = drops[i];
    if (drop.id === id) {
      return drop.marker;
    }
  }
};

SoapStone.DropView.prototype.showDropList = function (drops) {
  var self = this;
  $("[data-view='map']").append(this.dropListTemplate(drops));
  $(".drop-list").on('click', 'a', function(event){
    if (event.target.dataset.drop) {
      event.preventDefault();
      var dropId = event.target.dataset.drop;
      self.controller.showDrop(dropId);
    }
  });
  $(".drop-list").on('mouseenter', '.drop-item', function(event) {
    $(this).addClass("selected");
    var marker = self.getMarker(drops, Number(this.dataset.drop));
    marker.setAnimation(google.maps.Animation.BOUNCE);
  });
  $(".drop-list").on('mouseleave', '.drop-item', function(event) {
    $(this).removeClass("selected");
    var marker = self.getMarker(drops, Number(this.dataset.drop));
    marker.setAnimation(null);
  });
};

SoapStone.DropView.prototype.closeDrop  = function () {
  $("[data-view='drop']").remove();
  $("[data-menu='drop']").remove();
  $("[data-view='map']").show();
  $("[data-menu='map']").show();
};
<commit_msg>Add marker bounce on list select for touch/click<commit_after>//Drop Model
SoapStone.Drop = function (args) {
  if (args) {
    this.setAttributes(args);
  }
};

SoapStone.Drop.prototype.setAttributes = function (args) {
  this.id = args.id;
  if (args.coords) {
    this.coords = {};
    this.coords.longitude = args.coords.longitude;
    this.coords.latitude = args.coords.latitude;
  }
  if (args.lon && args.lat) {
    this.coords = {};
    this.coords.latitude = args.lat;
    this.coords.longitude = args.lon;
  }
  if (this.coords) {
    this.lat = this.coords.latitude;
    this.lon = this.coords.longitude;
  }
  this.text = args.text;
  this.photo = args.photo;
  this.distance = args.distance;
  this.has_photo = args["has_photo?"];
  this.created_at = args.created_at;
  this.snaps_count = args.snaps_count;
  this.comments_count = args.comments_count;
  this.snapped_by_you = args["snapped_by?"];
  if (args.user) {
    this.user = new SoapStone.User(args.user);
  }
  if (args.comments) {
    this.comments = args.comments.map(function (data) {
      return new SoapStone.Comment(data);
    });
  }
};

SoapStone.Drop.prototype.save = function (formData) {
  formData.append('drop[lat]', this.lat);
  formData.append('drop[lon]', this.lon);
  return $.ajax({
    type: "POST",
    url:  "/drops",
    cache: false,
    contentType: false,
    processData: false,
    data: formData
  });
};

SoapStone.Drop.prototype.find = function (id) {
  var self = this;
  return new Promise(function (resolve, reject) {
    $.ajax({
      type: "GET",
      url: "/drops/" + id,
      dataType: 'json'
     })
    .then(function (response) {
      self.setAttributes(response);
      resolve(self);
    })
    .fail(function () {
      reject();
    });
  });
};

SoapStone.Drop.prototype.addSnap = function () {
  var self = this;
  return $.ajax({
    type:"POST",
    url: "/drops/" + self.id + "/snaps"
  }).then(function () {
    self.snaps_count +=1;
    self.snapped_by_you = true;
  });
};

SoapStone.Drop.prototype.createComment = function (comment) {
  var self = this;
  return $.ajax({
    type:"POST",
    url: "/drops/" + self.id + "/comments",
    data:{comment: $("[data-form='comment-form']").val()}
  }).then(function (response) {
    self.comments.push(new SoapStone.Comment(response));
    self.comments_count += 1;
  });
};

SoapStone.Comment = function (args) {
  this.text = args.text;
  if (args.user) {
    this.user = {};
    this.user.id = args.user.id;
    this.user.username = args.user.username;
    this.user.avatar = args.user.avatar;
  }
};

// View
SoapStone.DropView = function () {
  this.showTemplate = Handlebars.compile($("[data-template='show-drop']").html());
  this.dropListTemplate = Handlebars.compile($("[data-template='drop-list']").html());
  Handlebars.registerPartial("snap-button", $("[data-partial='snap-button-partial']").html());
  this.snapButtonTemplate = Handlebars.compile($("[data-partial='snap-button-partial']").html());
  Handlebars.registerPartial("comment", $("[data-partial='comment-partial']").html());
  this.commentsTemplate = Handlebars.compile($("[data-partial='comment-partial']").html());
  this.setUpEventHandlers();
};

SoapStone.DropView.prototype.setUpEventHandlers = function () {
  var self = this;

  $("[data-role='drop-form']").on('submit', function (event) {
    event.preventDefault();
    self.controller.createDrop($("[data-role='drop-form']"));
  });

  $("[data-button='friend-filter']").on('click', function (e) {
    self.controller.loadDrops("/followees");
  });

  $("[data-button='public-filter']").on('click', function (e) {
    self.controller.loadDrops();
  });

  $("[data-button='new-button']").on('click', function (event) {
    event.preventDefault();
    self.showNewDropForm();
  });

  $("[data-button='close-form']").on('click', function (event) {
    event.preventDefault();
    self.hideNewDropForm();
  });
};

SoapStone.DropView.prototype.showNewDropForm = function () {
  $("[data-view='new-form']").show();
};

SoapStone.DropView.prototype.hideNewDropForm = function () {
  $("[data-view='new-form']").removeClass('uploading');
  $("[data-view='new-form']").hide();
};

SoapStone.DropView.prototype.showUploadIndicator = function () {
  $("[data-view='new-form']").addClass('uploading');
};

SoapStone.DropView.prototype.showUploadSuccess = function (response) {
  console.log("Drop posted successfuly!");
  toastr.success("Drop Posted", "Success");
  this.hideNewDropForm();
};

SoapStone.DropView.prototype.showUploadFailure = function (response) {
  console.log("Drop failed to post.");
  toastr.error("Drop failed to post.", "Error");
  this.hideNewDropForm();
};

SoapStone.DropView.prototype.updateSnapButton = function (drop) {
  $("[data-button='snap-button']").replaceWith(this.snapButtonTemplate(drop));
};

SoapStone.DropView.prototype.updateComments = function (drop) {
  $(".comment-list").replaceWith(this.commentsTemplate(drop));
};

SoapStone.DropView.prototype.showDrop = function (drop) {
  var self = this;
  $('body').append(this.showTemplate(drop));
  $("[data-view='map']").hide();
  $("[data-menu='map']").hide();
  $("[data-button='close-drop']").on('click', function (event) {
    self.closeDrop();
  });

  $("[data-button='snap-button']").on('click', function (event) {
    event.preventDefault();
    self.controller.addSnap(drop);
  });

  $("[data-button='comment-button']").on('click', function (event){
    event.preventDefault();
    self.controller.createComment(drop);
    $("[data-form='comment-form']").val('');
  });
};

SoapStone.DropView.prototype.clearDropList = function (drop) {
  $(".drop-list").remove();
};

SoapStone.DropView.prototype.getMarker = function (drops, id) {
  for (var i = 0; i < drops.length; i++) {
    var drop = drops[i];
    if (drop.id === id) {
      return drop.marker;
    }
  }
};

SoapStone.DropView.prototype.clearMarkerAnimations = function (drops) {
  for (var i = 0; i < drops.length; i++) {
    var drop = drops[i];
    drop.marker.setAnimation(null);
  }
};

SoapStone.DropView.prototype.showDropList = function (drops) {
  var self = this;
  $("[data-view='map']").append(this.dropListTemplate(drops));
  $(".drop-list").on('click', 'a', function(event){
    if (event.target.dataset.drop) {
      event.preventDefault();
      var dropId = event.target.dataset.drop;
      self.controller.showDrop(dropId);
    }
  });
  $(".drop-list").on('mouseenter', '.drop-item', function(event) {
    $(this).addClass("selected");
    var marker = self.getMarker(drops, Number(this.dataset.drop));
    marker.setAnimation(google.maps.Animation.BOUNCE);
  });
  $(".drop-list").on('mouseleave', '.drop-item', function(event) {
    $(this).removeClass("selected");
    var marker = self.getMarker(drops, Number(this.dataset.drop));
    marker.setAnimation(null);
  });
  $(".drop-list").on('click', '.drop-item', function(event) {
    $('.drop-item').removeClass("selected");
    $(this).addClass("selected");
    self.clearMarkerAnimations(drops);
    var marker = self.getMarker(drops, Number(this.dataset.drop));
    marker.setAnimation(google.maps.Animation.BOUNCE);
  });
};

SoapStone.DropView.prototype.closeDrop  = function () {
  $("[data-view='drop']").remove();
  $("[data-menu='drop']").remove();
  $("[data-view='map']").show();
  $("[data-menu='map']").show();
};
<|endoftext|>


<commit_before>define(['../EventEmitter'], function(EventEmitter) {
    // Set up the Jasmine environment
    var jasmineEnv = jasmine.getEnv();
    jasmineEnv.updateInterval = 1000;

    var htmlReporter = new jasmine.HtmlReporter();

    jasmineEnv.addReporter(htmlReporter);

    jasmineEnv.specFilter = function(spec) {
        return htmlReporter.specFilter(spec);
    };

    // Configure the tests
    describe('getListeners', function() {
        var ee;

        beforeEach(function() {
            ee = new EventEmitter();
        });

        it('initialises the event object and a listener array', function() {
            ee.getListeners('foo');
            expect(ee._events).toEqual({
                foo: []
            });
        });

        it('does not overwrite listener arrays', function() {
            var listeners = ee.getListeners('foo');
            listeners.push('bar');

            expect(ee._events).toEqual({
                foo: ['bar']
            });

            ee.getListeners('foo');

            expect(ee._events).toEqual({
                foo: ['bar']
            });
        });
    });

    describe('addListener', function() {
        var ee,
            fn1 = function(){},
            fn2 = function(){};

        beforeEach(function() {
            ee = new EventEmitter();
        });

        it('adds a listener to the specified event', function() {
            ee.addListener('foo', fn1);
            expect(ee.getListeners('foo')).toEqual([fn1]);
        });

        it('does not allow duplicate listeners', function() {
            ee.addListener('bar', fn1);
            expect(ee.getListeners('bar')).toEqual([fn1]);

            ee.addListener('bar', fn2);
            expect(ee.getListeners('bar')).toEqual([fn1, fn2]);

            ee.addListener('bar', fn1);
            expect(ee.getListeners('bar')).toEqual([fn1, fn2]);
        });
    });

    describe('removeListener', function() {
        var ee,
            fn1 = function(){},
            fn2 = function(){},
            fn3 = function(){},
            fn4 = function(){},
            fnX = function(){};

        beforeEach(function() {
            ee = new EventEmitter();
        });

        it('does nothing when the listener is not found', function() {
            var orig = ee.getListeners('foo').length;
            ee.removeListener('foo', fn1);
            expect(ee.getListeners('foo').length).toEqual(orig);
        });

        it('can handle removing events that have not been added', function() {
            expect(ee._events).toBeUndefined();
            ee.removeEvent('foo');
            expect(ee._events).not.toBeUndefined();
        });

        it('actually removes events', function() {
            ee.removeEvent('foo');
            expect(ee._events.foo).toBeUndefined();
        });

        it('removes listeners', function() {
            var listeners = ee.getListeners('bar');

            ee.addListener('bar', fn1);
            ee.addListener('bar', fn2);
            ee.addListener('bar', fn3);
            ee.addListener('bar', fn3); // Make sure doubling up does nothing
            ee.addListener('bar', fn4);
            expect(listeners).toEqual([fn1, fn2, fn3, fn4]);

            ee.removeListener('bar', fn3);
            expect(listeners).toEqual([fn1, fn2, fn4]);

            ee.removeListener('bar', fnX);
            expect(listeners).toEqual([fn1, fn2, fn4]);

            ee.removeListener('bar', fn1);
            expect(listeners).toEqual([fn2, fn4]);

            ee.removeListener('bar', fn4);
            expect(listeners).toEqual([fn2]);

            ee.removeListener('bar', fn2);
            expect(ee._events.bar).toEqual(null);
        });
    });

    describe('removeEvent', function() {
        var ee,
            fn1 = function(){},
            fn2 = function(){},
            fn3 = function(){},
            fn4 = function(){},
            fn5 = function(){};

        beforeEach(function() {
            ee = new EventEmitter();

            ee.addListener('foo', fn1);
            ee.addListener('foo', fn2);
            ee.addListener('bar', fn3);
            ee.addListener('bar', fn4);
            ee.addListener('baz', fn5);
            expect(ee.getListeners('foo')).toEqual([fn1, fn2]);
            expect(ee.getListeners('bar')).toEqual([fn3, fn4]);
            expect(ee.getListeners('baz')).toEqual([fn5]);
        });

        it('removes all listeners for the specified event', function() {
            ee.removeEvent('bar');
            expect(ee.getListeners('foo')).toEqual([fn1, fn2]);
            expect(ee.getListeners('bar')).toEqual([]);
            expect(ee.getListeners('baz')).toEqual([fn5]);

            ee.removeEvent('baz');
            expect(ee.getListeners('foo')).toEqual([fn1, fn2]);
            expect(ee.getListeners('bar')).toEqual([]);
            expect(ee.getListeners('baz')).toEqual([]);
        });

        it('removes all events when no event is specified', function() {
            ee.removeEvent();
            expect(ee.getListeners('foo')).toEqual([]);
            expect(ee.getListeners('bar')).toEqual([]);
            expect(ee.getListeners('baz')).toEqual([]);
        });
    });

    describe('emitEvent', function() {
        var ee;

        beforeEach(function() {
            ee = new EventEmitter();
        });

        it('executes attached listeners', function() {
            var run = false;

            ee.addListener('foo', function() {
                run = true;
            });
            ee.emitEvent('foo');

            expect(run).toEqual(true);
        });

        it('executes attached with a single argument', function() {
            var key = null;

            ee.addListener('bar', function(a) {
                key = a;
            });
            ee.emitEvent('bar', [50]);

            expect(key).toEqual(50);
        });

        it('executes attached with arguments', function() {
            var key = null;

            ee.addListener('bar2', function(a, b) {
                key = a + b;
            });
            ee.emitEvent('bar2', [40, 2]);

            expect(key).toEqual(42);
        });

        it('executes multiple listeners', function() {
            var count = 0;

            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', function() { count++; });

            ee.emitEvent('baz');

            expect(count).toEqual(5);
        });

        it('executes multiple listeners after one has been removed', function() {
            var count = 0,
                toRemove = function() { count++; };

            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', toRemove);
            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', function() { count++; });

            ee.removeListener('baz', toRemove);

            ee.emitEvent('baz');

            expect(count).toEqual(4);
        });

        it('executes multiple listeners and removes those that return true', function() {
            var count = 0;

            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', function() { count++; return true; });
            ee.addListener('baz', function() { count++; return false; });
            ee.addListener('baz', function() { count++; return 1; });
            ee.addListener('baz', function() { count++; return true; });

            ee.emitEvent('baz');
            ee.emitEvent('baz');

            expect(count).toEqual(8);
        });
    });

    describe('manipulateListeners', function() {
        var ee,
            fn1 = function(){},
            fn2 = function(){},
            fn3 = function(){},
            fn4 = function(){},
            fn5 = function(){};

        beforeEach(function() {
            ee = new EventEmitter();
        });

        it('manipulates multiple with an array', function() {
            ee.manipulateListeners(false, 'foo', [fn1, fn2, fn3, fn4, fn5]);
            expect(ee.getListeners('foo')).toEqual([fn5, fn4, fn3, fn2, fn1]);

            ee.manipulateListeners(true, 'foo', [fn1, fn2]);
            expect(ee.getListeners('foo')).toEqual([fn5, fn4, fn3]);

            ee.manipulateListeners(true, 'foo', [fn3, fn5]);
            ee.manipulateListeners(false, 'foo', [fn4, fn1]);
            expect(ee.getListeners('foo')).toEqual([fn4, fn1]);

            ee.manipulateListeners(true, 'foo', [fn4, fn1]);
            expect(ee.getListeners('foo')).toEqual([]);
        });

        it('manipulates with an object', function() {
            ee.manipulateListeners(false, {
                foo: [fn1, fn2, fn3],
                bar: fn4
            });

            ee.manipulateListeners(false, {
                bar: [fn5, fn1]
            });

            expect(ee.getListeners('foo')).toEqual([fn3, fn2, fn1]);
            expect(ee.getListeners('bar')).toEqual([fn4, fn1, fn5]);

            ee.manipulateListeners(true, {
                foo: fn1,
                bar: [fn5, fn4]
            });

            expect(ee.getListeners('foo')).toEqual([fn3, fn2]);
            expect(ee.getListeners('bar')).toEqual([fn1]);

            ee.manipulateListeners(true, {
                foo: [fn3, fn2],
                bar: fn1
            });

            expect(ee.getListeners('foo')).toEqual([]);
            expect(ee.getListeners('bar')).toEqual([]);
        });

        it('does not execute listeners just after they are added in another listeners', function() {
            var count = 0;

            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', function() {
                count++;

                ee.addListener('baz', function() {
                    count++;
                });
            });
            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', function() { count++; });

            ee.emitEvent('baz');

            expect(count).toEqual(5);
        });
    });

    describe('addListeners', function() {
        var ee,
            fn1 = function(){},
            fn2 = function(){},
            fn3 = function(){},
            fn4 = function(){},
            fn5 = function(){};

        beforeEach(function() {
            ee = new EventEmitter();
        });

        it('adds with an array', function() {
            ee.addListeners('foo', [fn1, fn2, fn3]);
            expect(ee.getListeners('foo')).toEqual([fn3, fn2, fn1]);

            ee.addListeners('foo', [fn4, fn5]);
            expect(ee.getListeners('foo')).toEqual([fn3, fn2, fn1, fn5, fn4]);
        });

        it('adds with an object', function() {
            ee.addListeners({
                foo: fn1,
                bar: [fn2, fn3]
            });
            expect(ee.getListeners('foo')).toEqual([fn1]);
            expect(ee.getListeners('bar')).toEqual([fn3, fn2]);

            ee.addListeners({
                foo: [fn4],
                bar: fn5
            });
            expect(ee.getListeners('foo')).toEqual([fn1, fn4]);
            expect(ee.getListeners('bar')).toEqual([fn3, fn2, fn5]);
        });
    });

    describe('removeListeners', function() {
        var ee,
            fn1 = function(){},
            fn2 = function(){},
            fn3 = function(){},
            fn4 = function(){},
            fn5 = function(){};

        beforeEach(function() {
            ee = new EventEmitter();
        });

        it('removes with an array', function() {
            ee.addListeners('foo', [fn1, fn2, fn3, fn4, fn5]);
            ee.removeListeners('foo', [fn2, fn3]);
            expect(ee.getListeners('foo')).toEqual([fn5, fn4, fn1]);

            ee.removeListeners('foo', [fn5, fn4]);
            expect(ee.getListeners('foo')).toEqual([fn1]);

            ee.removeListeners('foo', [fn1]);
            expect(ee.getListeners('foo')).toEqual([]);
        });

        it('removes with an object', function() {
            ee.addListeners({
                foo: [fn1, fn2, fn3, fn4, fn5],
                bar: [fn1, fn2, fn3, fn4, fn5]
            });

            ee.removeListeners({
                foo: fn2,
                bar: [fn3, fn4, fn5]
            });
            expect(ee.getListeners('foo')).toEqual([fn5, fn4, fn3, fn1]);
            expect(ee.getListeners('bar')).toEqual([fn2, fn1]);

            ee.removeListeners({
                foo: [fn3],
                bar: [fn2, fn1]
            });
            expect(ee.getListeners('foo')).toEqual([fn5, fn4, fn1]);
            expect(ee.getListeners('bar')).toEqual([]);
        });
    });

    // Run Jasmine
    jasmineEnv.execute();
});<commit_msg>Added a test for the new emit method.<commit_after>define(['../EventEmitter'], function(EventEmitter) {
    // Set up the Jasmine environment
    var jasmineEnv = jasmine.getEnv();
    jasmineEnv.updateInterval = 1000;

    var htmlReporter = new jasmine.HtmlReporter();

    jasmineEnv.addReporter(htmlReporter);

    jasmineEnv.specFilter = function(spec) {
        return htmlReporter.specFilter(spec);
    };

    // Configure the tests
    describe('getListeners', function() {
        var ee;

        beforeEach(function() {
            ee = new EventEmitter();
        });

        it('initialises the event object and a listener array', function() {
            ee.getListeners('foo');
            expect(ee._events).toEqual({
                foo: []
            });
        });

        it('does not overwrite listener arrays', function() {
            var listeners = ee.getListeners('foo');
            listeners.push('bar');

            expect(ee._events).toEqual({
                foo: ['bar']
            });

            ee.getListeners('foo');

            expect(ee._events).toEqual({
                foo: ['bar']
            });
        });
    });

    describe('addListener', function() {
        var ee,
            fn1 = function(){},
            fn2 = function(){};

        beforeEach(function() {
            ee = new EventEmitter();
        });

        it('adds a listener to the specified event', function() {
            ee.addListener('foo', fn1);
            expect(ee.getListeners('foo')).toEqual([fn1]);
        });

        it('does not allow duplicate listeners', function() {
            ee.addListener('bar', fn1);
            expect(ee.getListeners('bar')).toEqual([fn1]);

            ee.addListener('bar', fn2);
            expect(ee.getListeners('bar')).toEqual([fn1, fn2]);

            ee.addListener('bar', fn1);
            expect(ee.getListeners('bar')).toEqual([fn1, fn2]);
        });
    });

    describe('removeListener', function() {
        var ee,
            fn1 = function(){},
            fn2 = function(){},
            fn3 = function(){},
            fn4 = function(){},
            fnX = function(){};

        beforeEach(function() {
            ee = new EventEmitter();
        });

        it('does nothing when the listener is not found', function() {
            var orig = ee.getListeners('foo').length;
            ee.removeListener('foo', fn1);
            expect(ee.getListeners('foo').length).toEqual(orig);
        });

        it('can handle removing events that have not been added', function() {
            expect(ee._events).toBeUndefined();
            ee.removeEvent('foo');
            expect(ee._events).not.toBeUndefined();
        });

        it('actually removes events', function() {
            ee.removeEvent('foo');
            expect(ee._events.foo).toBeUndefined();
        });

        it('removes listeners', function() {
            var listeners = ee.getListeners('bar');

            ee.addListener('bar', fn1);
            ee.addListener('bar', fn2);
            ee.addListener('bar', fn3);
            ee.addListener('bar', fn3); // Make sure doubling up does nothing
            ee.addListener('bar', fn4);
            expect(listeners).toEqual([fn1, fn2, fn3, fn4]);

            ee.removeListener('bar', fn3);
            expect(listeners).toEqual([fn1, fn2, fn4]);

            ee.removeListener('bar', fnX);
            expect(listeners).toEqual([fn1, fn2, fn4]);

            ee.removeListener('bar', fn1);
            expect(listeners).toEqual([fn2, fn4]);

            ee.removeListener('bar', fn4);
            expect(listeners).toEqual([fn2]);

            ee.removeListener('bar', fn2);
            expect(ee._events.bar).toEqual(null);
        });
    });

    describe('removeEvent', function() {
        var ee,
            fn1 = function(){},
            fn2 = function(){},
            fn3 = function(){},
            fn4 = function(){},
            fn5 = function(){};

        beforeEach(function() {
            ee = new EventEmitter();

            ee.addListener('foo', fn1);
            ee.addListener('foo', fn2);
            ee.addListener('bar', fn3);
            ee.addListener('bar', fn4);
            ee.addListener('baz', fn5);
            expect(ee.getListeners('foo')).toEqual([fn1, fn2]);
            expect(ee.getListeners('bar')).toEqual([fn3, fn4]);
            expect(ee.getListeners('baz')).toEqual([fn5]);
        });

        it('removes all listeners for the specified event', function() {
            ee.removeEvent('bar');
            expect(ee.getListeners('foo')).toEqual([fn1, fn2]);
            expect(ee.getListeners('bar')).toEqual([]);
            expect(ee.getListeners('baz')).toEqual([fn5]);

            ee.removeEvent('baz');
            expect(ee.getListeners('foo')).toEqual([fn1, fn2]);
            expect(ee.getListeners('bar')).toEqual([]);
            expect(ee.getListeners('baz')).toEqual([]);
        });

        it('removes all events when no event is specified', function() {
            ee.removeEvent();
            expect(ee.getListeners('foo')).toEqual([]);
            expect(ee.getListeners('bar')).toEqual([]);
            expect(ee.getListeners('baz')).toEqual([]);
        });
    });

    describe('emitEvent', function() {
        var ee;

        beforeEach(function() {
            ee = new EventEmitter();
        });

        it('executes attached listeners', function() {
            var run = false;

            ee.addListener('foo', function() {
                run = true;
            });
            ee.emitEvent('foo');

            expect(run).toEqual(true);
        });

        it('executes attached with a single argument', function() {
            var key = null;

            ee.addListener('bar', function(a) {
                key = a;
            });
            ee.emitEvent('bar', [50]);

            expect(key).toEqual(50);

            ee.emit('bar', 60);
            expect(key).toEqual(60);
        });

        it('executes attached with arguments', function() {
            var key = null;

            ee.addListener('bar2', function(a, b) {
                key = a + b;
            });
            ee.emitEvent('bar2', [40, 2]);

            expect(key).toEqual(42);
        });

        it('executes multiple listeners', function() {
            var count = 0;

            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', function() { count++; });

            ee.emitEvent('baz');

            expect(count).toEqual(5);
        });

        it('executes multiple listeners after one has been removed', function() {
            var count = 0,
                toRemove = function() { count++; };

            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', toRemove);
            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', function() { count++; });

            ee.removeListener('baz', toRemove);

            ee.emitEvent('baz');

            expect(count).toEqual(4);
        });

        it('executes multiple listeners and removes those that return true', function() {
            var count = 0;

            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', function() { count++; return true; });
            ee.addListener('baz', function() { count++; return false; });
            ee.addListener('baz', function() { count++; return 1; });
            ee.addListener('baz', function() { count++; return true; });

            ee.emitEvent('baz');
            ee.emitEvent('baz');

            expect(count).toEqual(8);
        });
    });

    describe('manipulateListeners', function() {
        var ee,
            fn1 = function(){},
            fn2 = function(){},
            fn3 = function(){},
            fn4 = function(){},
            fn5 = function(){};

        beforeEach(function() {
            ee = new EventEmitter();
        });

        it('manipulates multiple with an array', function() {
            ee.manipulateListeners(false, 'foo', [fn1, fn2, fn3, fn4, fn5]);
            expect(ee.getListeners('foo')).toEqual([fn5, fn4, fn3, fn2, fn1]);

            ee.manipulateListeners(true, 'foo', [fn1, fn2]);
            expect(ee.getListeners('foo')).toEqual([fn5, fn4, fn3]);

            ee.manipulateListeners(true, 'foo', [fn3, fn5]);
            ee.manipulateListeners(false, 'foo', [fn4, fn1]);
            expect(ee.getListeners('foo')).toEqual([fn4, fn1]);

            ee.manipulateListeners(true, 'foo', [fn4, fn1]);
            expect(ee.getListeners('foo')).toEqual([]);
        });

        it('manipulates with an object', function() {
            ee.manipulateListeners(false, {
                foo: [fn1, fn2, fn3],
                bar: fn4
            });

            ee.manipulateListeners(false, {
                bar: [fn5, fn1]
            });

            expect(ee.getListeners('foo')).toEqual([fn3, fn2, fn1]);
            expect(ee.getListeners('bar')).toEqual([fn4, fn1, fn5]);

            ee.manipulateListeners(true, {
                foo: fn1,
                bar: [fn5, fn4]
            });

            expect(ee.getListeners('foo')).toEqual([fn3, fn2]);
            expect(ee.getListeners('bar')).toEqual([fn1]);

            ee.manipulateListeners(true, {
                foo: [fn3, fn2],
                bar: fn1
            });

            expect(ee.getListeners('foo')).toEqual([]);
            expect(ee.getListeners('bar')).toEqual([]);
        });

        it('does not execute listeners just after they are added in another listeners', function() {
            var count = 0;

            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', function() {
                count++;

                ee.addListener('baz', function() {
                    count++;
                });
            });
            ee.addListener('baz', function() { count++; });
            ee.addListener('baz', function() { count++; });

            ee.emitEvent('baz');

            expect(count).toEqual(5);
        });
    });

    describe('addListeners', function() {
        var ee,
            fn1 = function(){},
            fn2 = function(){},
            fn3 = function(){},
            fn4 = function(){},
            fn5 = function(){};

        beforeEach(function() {
            ee = new EventEmitter();
        });

        it('adds with an array', function() {
            ee.addListeners('foo', [fn1, fn2, fn3]);
            expect(ee.getListeners('foo')).toEqual([fn3, fn2, fn1]);

            ee.addListeners('foo', [fn4, fn5]);
            expect(ee.getListeners('foo')).toEqual([fn3, fn2, fn1, fn5, fn4]);
        });

        it('adds with an object', function() {
            ee.addListeners({
                foo: fn1,
                bar: [fn2, fn3]
            });
            expect(ee.getListeners('foo')).toEqual([fn1]);
            expect(ee.getListeners('bar')).toEqual([fn3, fn2]);

            ee.addListeners({
                foo: [fn4],
                bar: fn5
            });
            expect(ee.getListeners('foo')).toEqual([fn1, fn4]);
            expect(ee.getListeners('bar')).toEqual([fn3, fn2, fn5]);
        });
    });

    describe('removeListeners', function() {
        var ee,
            fn1 = function(){},
            fn2 = function(){},
            fn3 = function(){},
            fn4 = function(){},
            fn5 = function(){};

        beforeEach(function() {
            ee = new EventEmitter();
        });

        it('removes with an array', function() {
            ee.addListeners('foo', [fn1, fn2, fn3, fn4, fn5]);
            ee.removeListeners('foo', [fn2, fn3]);
            expect(ee.getListeners('foo')).toEqual([fn5, fn4, fn1]);

            ee.removeListeners('foo', [fn5, fn4]);
            expect(ee.getListeners('foo')).toEqual([fn1]);

            ee.removeListeners('foo', [fn1]);
            expect(ee.getListeners('foo')).toEqual([]);
        });

        it('removes with an object', function() {
            ee.addListeners({
                foo: [fn1, fn2, fn3, fn4, fn5],
                bar: [fn1, fn2, fn3, fn4, fn5]
            });

            ee.removeListeners({
                foo: fn2,
                bar: [fn3, fn4, fn5]
            });
            expect(ee.getListeners('foo')).toEqual([fn5, fn4, fn3, fn1]);
            expect(ee.getListeners('bar')).toEqual([fn2, fn1]);

            ee.removeListeners({
                foo: [fn3],
                bar: [fn2, fn1]
            });
            expect(ee.getListeners('foo')).toEqual([fn5, fn4, fn1]);
            expect(ee.getListeners('bar')).toEqual([]);
        });
    });

    // Run Jasmine
    jasmineEnv.execute();
});<|endoftext|>


<commit_before>define(['jquery', 'appearanceUtils'], function($, utils) {
   return {
      navbar: "#restore-buttons",
      page_indicator_box: "#global-indicators",
      page_indicators: {
         pull_count: function(pulls, node) {
            node.text(pulls.length + " open pulls");
            node.wrapInner('');
         }
      },
      // Global filters
      // where
      selector: function(pull) {
         return pull.state == 'open';
      },
      // order by
      sort: function(pull) {
         return pull.created_at;
      },
      // Allows custom modifications of each pull's display
      adjust: function(pull, node) {
         // If the pull is over 30 days old...
         if (Date.now() - (new Date(pull.created_at)) > 2590000000 ) {
            // Mark it in red
            $(node).addClass('bg-warning');
         }
      },
      // Functions to stick status information in indicators at the bottom of each pull
      indicators: {
         cr_remaining: function cr_remaining(pull, node) {
            var required = pull.status.cr_req;
            var completed = pull.status.CR.length;

            var text = $('
CR ' + completed + '/' + required + '
');

            node.append(text);

            if (completed >= required) {
               text.addClass('text-success');
            }

            pull.status.CR.forEach(function(signature) {
               var user = signature.data.user;
               node.append(utils.getAvatarDOMNode(user.login, user.id));
            });
         },
         qa_remaining: function qa_remaining(pull, node) {
            var required = pull.status.qa_req;
            var completed = pull.status.QA.length;

            var text = $('
QA ' + completed + '/' + required + '
');

            node.append(text);

            if (completed >= required) {
               text.addClass('text-success');
            }

            pull.status.QA.forEach(function(signature) {
               var user = signature.data.user;
               node.append(utils.getAvatarDOMNode(user.login, user.id));
            });
         },
         status: function status(pull, node) {
            if (pull.status.commit_status) {
            var commit_status = pull.status.commit_status.data;
               var title = commit_status.description;
               var url   = commit_status.target_url;
               var state = commit_status.state;

               var link = $('');
               node.append(link);
               link.tooltip();
               switch(commit_status.state) {
                  case 'pending':
                  link.append('');
                  break;
                  case 'success':
                  link.append('');
                  break;
                  case 'error':
                  link.append('');
                  break;
                  case 'failure':
                  link.append('');
                  break;
               }
            }
         },
         user_icon: function user_icon(pull, node) {
            if (pull.is_mine()) {
               node.append('');
            }
         }
      },
      columns: [
         {
            title: "CI Unsuccessful",
            id: "ciUnsuccessful",
            selector: function(pull) {
               return pull.build_status() != 'success' && !pull.dev_blocked();
            },
            sort: function(pull) {
               var score = 0;
               if (pull.is_mine()) {
                  score -= 15;
               }

               score -= pull.status.CR.length * 1;
               score -= pull.status.QA.length * 2;

               if (!pull.status.commit_status) {
                  score += 15;
               }

               return score;
            },
            triggers: {
               onCreate: function(blob, container) {
                  blob.removeClass('panel-default').addClass('panel-primary');
               },
               onUpdate: function(blob, container) {
                  utils.hideIfEmpty(container, blob, '.pull');
               }
            },
            shrinkToButton: true
         },
         {
            title: "deploy_blocked Pulls",
            id: "deployBlockPulls",
            selector: function(pull) {
               return pull.deploy_blocked() && !pull.dev_blocked();
            },
            adjust: function(pull, node) {
               node.addClass('list-group-item-danger');
            },
            triggers: {
               onCreate: function(blob, container) {
                  blob.removeClass('panel-default').addClass('panel-primary');
               },
               onUpdate: function(blob, container) {
                  utils.hideIfEmpty(container, blob, '.pull');
               }
            },
            shrinkToButton: true
         },
         {
            title: "Ready Pulls",
            id: "readyPulls",
            selector: function(pull) {
               return pull.status.ready && !pull.dev_blocked() && pull.build_status() == 'success';
            },
            adjust: function(pull, node) {
               node.addClass('list-group-item-success');
            },
            triggers: {
               onCreate: function(blob, container) {
                  blob.removeClass('panel-default').addClass('panel-primary');
               },
               onUpdate: function(blob, container) {
                  utils.hideIfEmpty(container, blob, '.pull');
               }
            },
            shrinkToButton: true
         },
         {
            title: "dev_blocked Pulls",
            id: "blockPulls",
            selector: function(pull) {
               return pull.dev_blocked() ||
                (pull.cr_done() && pull.build_status() != 'success');
            },
            sort: function(pull) {
               return pull.is_mine() ? 0 : 1;
            }
         },
         {
            title: "CR Pulls",
            id: "crPulls",
            selector: function(pull) {
               return !pull.cr_done() && !pull.dev_blocked();
            },
            sort: function(pull) {
               if (pull.is_mine()) {
                  return 3;
               } else if (pull.qa_done() && pull.build_status() == 'success') {
                  return 0;
               } else if (pull.qa_done()) {
                  return 1;
               } else {
                  return 2;
               }
            },
            indicators: {
               cr_remaining: function(pull, node) {
                  var required = pull.status.cr_req;
                  var remaining = required - pull.status.CR.length;
               },
               qa_remaining: function(pull, node) {
                  var required = pull.status.qa_req;
                  var remaining = required - pull.status.QA.length;

                  if (remaining <= 0) {
                     node.children('.sig-count').addClass('text-success');
                  }
               }
            }
         },
         {
            title: "QA Pulls",
            id: "qaPulls",
            selector: function(pull) {
               var isHotfix = /^hotfix/.test(pull.head.ref);
               var numCRs = pull.status.CR.length;

               return !pull.qa_done() && !pull.dev_blocked() &&
                (numCRs > 0 || isHotfix) && pull.build_status() == 'success';
            },
            sort: function(pull) {
               if (pull.is_mine()) {
                  return 3;
               } else if (pull.cr_done() && pull.build_status() == 'success') {
                  return 0;
               } else if (pull.cr_done()) {
                  return 1;
               } else {
                  return 2;
               }
            },
            indicators: {
               qa_remaining: function(pull, node) {
                  var required = pull.status.qa_req;
                  var remaining = required - pull.status.QA.length;
               },
               cr_remaining: function(pull, node) {
                  var required = pull.status.cr_req;
                  var remaining = required - pull.status.CR.length;

                  if (remaining <= 0) {
                     node.children('.sig-count').addClass('text-success');
                  }
               }
            }

         }
      ]
   };
});
<commit_msg>Remove per-column setting of QA or CR to green<commit_after>define(['jquery', 'appearanceUtils'], function($, utils) {
   return {
      navbar: "#restore-buttons",
      page_indicator_box: "#global-indicators",
      page_indicators: {
         pull_count: function(pulls, node) {
            node.text(pulls.length + " open pulls");
            node.wrapInner('');
         }
      },
      // Global filters
      // where
      selector: function(pull) {
         return pull.state == 'open';
      },
      // order by
      sort: function(pull) {
         return pull.created_at;
      },
      // Allows custom modifications of each pull's display
      adjust: function(pull, node) {
         // If the pull is over 30 days old...
         if (Date.now() - (new Date(pull.created_at)) > 2590000000 ) {
            // Mark it in red
            $(node).addClass('bg-warning');
         }
      },
      // Functions to stick status information in indicators at the bottom of each pull
      indicators: {
         cr_remaining: function cr_remaining(pull, node) {
            var required = pull.status.cr_req;
            var completed = pull.status.CR.length;

            var text = $('
CR ' + completed + '/' + required + '
');

            node.append(text);

            if (completed >= required) {
               text.addClass('text-success');
            }

            pull.status.CR.forEach(function(signature) {
               var user = signature.data.user;
               node.append(utils.getAvatarDOMNode(user.login, user.id));
            });
         },
         qa_remaining: function qa_remaining(pull, node) {
            var required = pull.status.qa_req;
            var completed = pull.status.QA.length;

            var text = $('
QA ' + completed + '/' + required + '
');

            node.append(text);

            if (completed >= required) {
               text.addClass('text-success');
            }

            pull.status.QA.forEach(function(signature) {
               var user = signature.data.user;
               node.append(utils.getAvatarDOMNode(user.login, user.id));
            });
         },
         status: function status(pull, node) {
            if (pull.status.commit_status) {
            var commit_status = pull.status.commit_status.data;
               var title = commit_status.description;
               var url   = commit_status.target_url;
               var state = commit_status.state;

               var link = $('');
               node.append(link);
               link.tooltip();
               switch(commit_status.state) {
                  case 'pending':
                  link.append('');
                  break;
                  case 'success':
                  link.append('');
                  break;
                  case 'error':
                  link.append('');
                  break;
                  case 'failure':
                  link.append('');
                  break;
               }
            }
         },
         user_icon: function user_icon(pull, node) {
            if (pull.is_mine()) {
               node.append('');
            }
         }
      },
      columns: [
         {
            title: "CI Unsuccessful",
            id: "ciUnsuccessful",
            selector: function(pull) {
               return pull.build_status() != 'success' && !pull.dev_blocked();
            },
            sort: function(pull) {
               var score = 0;
               if (pull.is_mine()) {
                  score -= 15;
               }

               score -= pull.status.CR.length * 1;
               score -= pull.status.QA.length * 2;

               if (!pull.status.commit_status) {
                  score += 15;
               }

               return score;
            },
            triggers: {
               onCreate: function(blob, container) {
                  blob.removeClass('panel-default').addClass('panel-primary');
               },
               onUpdate: function(blob, container) {
                  utils.hideIfEmpty(container, blob, '.pull');
               }
            },
            shrinkToButton: true
         },
         {
            title: "deploy_blocked Pulls",
            id: "deployBlockPulls",
            selector: function(pull) {
               return pull.deploy_blocked() && !pull.dev_blocked();
            },
            adjust: function(pull, node) {
               node.addClass('list-group-item-danger');
            },
            triggers: {
               onCreate: function(blob, container) {
                  blob.removeClass('panel-default').addClass('panel-primary');
               },
               onUpdate: function(blob, container) {
                  utils.hideIfEmpty(container, blob, '.pull');
               }
            },
            shrinkToButton: true
         },
         {
            title: "Ready Pulls",
            id: "readyPulls",
            selector: function(pull) {
               return pull.status.ready && !pull.dev_blocked() && pull.build_status() == 'success';
            },
            adjust: function(pull, node) {
               node.addClass('list-group-item-success');
            },
            triggers: {
               onCreate: function(blob, container) {
                  blob.removeClass('panel-default').addClass('panel-primary');
               },
               onUpdate: function(blob, container) {
                  utils.hideIfEmpty(container, blob, '.pull');
               }
            },
            shrinkToButton: true
         },
         {
            title: "dev_blocked Pulls",
            id: "blockPulls",
            selector: function(pull) {
               return pull.dev_blocked() ||
                (pull.cr_done() && pull.build_status() != 'success');
            },
            sort: function(pull) {
               return pull.is_mine() ? 0 : 1;
            }
         },
         {
            title: "CR Pulls",
            id: "crPulls",
            selector: function(pull) {
               return !pull.cr_done() && !pull.dev_blocked();
            },
            sort: function(pull) {
               if (pull.is_mine()) {
                  return 3;
               } else if (pull.qa_done() && pull.build_status() == 'success') {
                  return 0;
               } else if (pull.qa_done()) {
                  return 1;
               } else {
                  return 2;
               }
            },
            indicators: {
               cr_remaining: function(pull, node) {
                  var required = pull.status.cr_req;
                  var remaining = required - pull.status.CR.length;
               }
            }
         },
         {
            title: "QA Pulls",
            id: "qaPulls",
            selector: function(pull) {
               var isHotfix = /^hotfix/.test(pull.head.ref);
               var numCRs = pull.status.CR.length;

               return !pull.qa_done() && !pull.dev_blocked() &&
                (numCRs > 0 || isHotfix) && pull.build_status() == 'success';
            },
            sort: function(pull) {
               if (pull.is_mine()) {
                  return 3;
               } else if (pull.cr_done() && pull.build_status() == 'success') {
                  return 0;
               } else if (pull.cr_done()) {
                  return 1;
               } else {
                  return 2;
               }
            },
            indicators: {
               qa_remaining: function(pull, node) {
                  var required = pull.status.qa_req;
                  var remaining = required - pull.status.QA.length;
               }
            }

         }
      ]
   };
});
<|endoftext|>


<commit_before>var fs = require('fs');
var mime = require('mime');
var path = require('path');

module.exports = function(grunt) {
  grunt.registerMultiTask('lyriaAssetList', function() {
    var files = this.files;
    var options = this.options({
      namespace: 'mygame',
      name: 'assetlist',
      ignores: ['scenes', 'i18n', 'prefabs', 'gameobjects', 'prefabs']
    });

    var assetObject = {};
    var assetSize = 0;

    for (var i = 0, j = files.length; i < j; i++) {

      (function(fileObject) {

        var dest = fileObject.dest;

        for ( k = 0, l = fileObject.src.length; k < l; k++) {
          (function(file) {
            var dirname = (file.split('/')[1].indexOf('.') > 0) ? 'root' : file.split('/')[1];

            if (options.ignores.indexOf(dirname) >= 0) {
              return;
            }

            assetObject[dirname] = assetObject[dirname] || {};
            stat = fs.statSync(file);
            assetObject[dirname].files = assetObject[dirname].files || [];
            assetObject[dirname].files.push({
              name: file,
              type: mime.lookup(file),
              size: stat.size
            });

            if (assetObject[dirname].totalSize) {
              assetObject[dirname].totalSize += stat.size;
            } else {
              assetObject[dirname].totalSize = stat.size;
            }
          })(fileObject.src[k]);
        }

        var value;
        for (var key in assetObject) {
          value = assetObject[key];

          assetSize += value.totalSize;
        }

        if (assetSize) {
          assetObject.totalSize = assetSize;
        }

        grunt.file.write(dest, 'define("' + options.namespace + '/' + options.name + '",' + JSON.stringify(assetObject) + ');');

      })(files[i]);

    }

  });
};<commit_msg>Try to update asset task to be more compliant to the official grunt task plugin spec<commit_after>var fs = require('fs');
var mime = require('mime');
var path = require('path');

module.exports = function(grunt) {
  grunt.registerMultiTask('lyriaAssetList', function() {
    var files = this.files;
    var options = this.options({
      namespace: 'mygame',
      name: 'assetlist',
      ignores: ['scenes', 'i18n', 'prefabs', 'gameobjects', 'prefabs']
    });

    var assetObject = {};
    var assetSize = 0;

    // Iterate over all specified file groups.
    this.files.forEach(function(f) {

      // Concat specified files.
      var src = f.src.filter(function(filepath) {
        // Warn on and remove invalid source files (if nonull was set).
        if (!grunt.file.exists(filepath)) {
          grunt.log.warn('Source file "' + filepath + '" not found.');
          return false;
        } else {
          return true;
        }
      }).map(function(filepath) {
        // Read file source.
        var dirname = (filepath.split('/')[1].indexOf('.') > 0) ? 'root' : filepath.split('/')[1];

        if (options.ignores.indexOf(dirname) >= 0) {
          return;
        }

        assetObject[dirname] = assetObject[dirname] || {};
        stat = fs.statSync(file);
        assetObject[dirname].files = assetObject[dirname].files || [];
        assetObject[dirname].files.push({
          name: file,
          type: mime.lookup(file),
          size: stat.size
        });

        if (assetObject[dirname].totalSize) {
          assetObject[dirname].totalSize += stat.size;
        } else {
          assetObject[dirname].totalSize = stat.size;
        }

      });

      for ( k = 0, l = fileObject.src.length; k < l; k++) {
          (function(file) {

          })(fileObject.src[k]);
        }

        var value;
        for (var key in assetObject) {
          value = assetObject[key];

          assetSize += value.totalSize;
        }

        if (assetSize) {
          assetObject.totalSize = assetSize;
        }

        grunt.file.write(dest, 'define("' + options.namespace + '/' + options.name + '",' + JSON.stringify(assetObject) + ');');

      // Write the destination file.
      grunt.file.write(f.dest, src);

      // Print a success message.
      grunt.log.writeln('File "' + f.dest + '" created.');
    });

  });
};<|endoftext|>


<commit_before>function locale() {
  return localStorage.locale || window.navigator.language.split('-')[0] || 'en';
}

function units() {
  return localStorage.units || 'metric';
}

function city() {
  return localStorage.city || '';
}

function poll(path, callback) {
  console.log('wait ' + path);

  $.get(path, function(data, textStatus, jqXHR) {
    if (jqXHR.status === 200) {
      console.log('goto ' + path);
      callback();
    } else {
      setTimeout(function() { poll(path, callback) }, 2000);
    }
  });
}

function querystring(str) {
  var strings = str.substring(1).split('&');
  var params = {};
  var i, n;

  for (i = 0, n = strings.length; i < n; i++) {
    var kv = strings[i].split('=');

    params[kv[0]] = kv[1];
  }
  return params;
}

function redirectToBulletin(params) {
  var path = '/bulletin?' + $.param(params);

  poll(path, function() {
    Turbolinks.visit(path);
  });
}

$(document).on('ready page:load', function() {
  var params = {
    date: querystring(window.location.search).date || 'today',
  };

  $('#settings form [name=city]').val(city());

  if (window.location.pathname === '/') {
    params.locale = locale();
    params.units = units();

    if (city()) {
      params.city = city();
      redirectToBulletin(params);
    } else {
      console.log('waiting for geolocation');
      navigator.geolocation.getCurrentPosition(function(pos) {
        console.log('geolocation found');
        params.latitude = pos.coords.latitude.toFixed(2);
        params.longitude = pos.coords.longitude.toFixed(2);
        redirectToBulletin(params);
      });
    }
  }

  $('#settings form').submit(function(e) {
    e.preventDefault();
    params.latitude = $('#settings form [name=latitude]').val();
    params.longitude = $('#settings form [name=longitude]').val();
    params.city = $('#settings form [name=city]').val();
    params.locale = $('#settings form [name=locale]').val();
    params.units = $('#settings form [name=units]').val();
    if (params.city) {
      localStorage.city = params.city;
      delete params.latitude;
      delete params.longitude;
    } else {
      delete localStorage.city;
      delete params.city;
    }
    localStorage.locale = params.locale;
    localStorage.units = params.units;
    Turbolinks.visit('/');
  });
});
<commit_msg>Refactor javascript<commit_after>var settings = {
  locale: window.navigator.language.split('-')[0] || 'en',
  units: 'metric',
  city: ''
};

function restoreSettings() {
  for (k in settings) {
    settings[k] = localStorage[k] || settings[k];
  }
}

function querystring(str) {
  var strings = str.substring(1).split('&');
  var params = {};
  var i, n;

  for (i = 0, n = strings.length; i < n; i++) {
    var kv = strings[i].split('=');

    params[kv[0]] = kv[1];
  }
  return params;
}

$(document).on('ready page:load', function() {
  var params = {
    date: querystring(window.location.search).date || 'today',
  };

  restoreSettings();
  $('#settings form [name=city]').val(settings.city);

  if (window.location.pathname === '/') {
    params.locale = settings.locale;
    params.units = settings.units;

    if (settings.city) {
      params.city = settings.city;
      path = '/bulletin?' + $.param(params);
      Turbolinks.visit('/bulletin?' + $.param(params));
    } else {
      console.log('waiting for geolocation');
      navigator.geolocation.getCurrentPosition(function(pos) {
        console.log('geolocation found');
        params.latitude = pos.coords.latitude.toFixed(2);
        params.longitude = pos.coords.longitude.toFixed(2);
      });
      Turbolinks.visit('/bulletin?' + $.param(params));
    }
  }

  $('#settings form').submit(function(e) {
    e.preventDefault();
    params.latitude = $('#settings form [name=latitude]').val();
    params.longitude = $('#settings form [name=longitude]').val();
    params.city = $('#settings form [name=city]').val();
    params.locale = $('#settings form [name=locale]').val();
    params.units = $('#settings form [name=units]').val();
    if (params.city) {
      localStorage.city = params.city;
      delete params.latitude;
      delete params.longitude;
    } else {
      delete localStorage.city;
      delete params.city;
    }
    localStorage.locale = params.locale;
    localStorage.units = params.units;
    Turbolinks.visit('/');
  });
});
<|endoftext|>


<commit_before>/**
 * Helper methods for tests.
 */

import { NodePath } from 'ast-types';
import buildParser from '../src/babelParser';

function stringify(value) {
  if (Array.isArray(value)) {
    return value.join('\n');
  }
  return value;
}

export function getParser(options = {}) {
  return buildParser(options);
}
/**
 * Returns a NodePath to the program node of the passed node
 */
export function parse(src, options = {}) {
  const ast = getParser(options).parse(stringify(src));
  ast.__src = src;

  return new NodePath(ast).get('program');
}

export function statement(src, options) {
  return parse(src, options).get('body', 0);
}

export function expression(src, options) {
  return statement('(' + src + ')', options).get('expression');
}

/**
 * Injects src into template by replacing the occurrence of %s.
 */
export function parseWithTemplate(src, template) {
  return parse(template.replace('%s', stringify(src)));
}

/**
 * Default template that simply defines React and PropTypes.
 */
export const REACT_TEMPLATE = [
  'var React = require("React");',
  'var PropTypes = React.PropTypes;',
  'var {PropTypes: OtherPropTypes} = require("React");',
  '%s;',
].join('\n');

export const MODULE_TEMPLATE = [
  'var React = require("React");',
  'var PropTypes = React.PropTypes;',
  'var Component = React.createClass(%s);',
  'module.exports = Component',
].join('\n');

/**
 * Importer that doesn't resolve any values
 */
export function noopImporter() {
  return null;
}
<commit_msg>Add mockImporter builder util<commit_after>/**
 * Helper methods for tests.
 */

import { NodePath } from 'ast-types';
import buildParser from '../src/babelParser';

function stringify(value) {
  if (Array.isArray(value)) {
    return value.join('\n');
  }
  return value;
}

export function getParser(options = {}) {
  return buildParser(options);
}
/**
 * Returns a NodePath to the program node of the passed node
 */
export function parse(src, options = {}) {
  const ast = getParser(options).parse(stringify(src));
  ast.__src = src;

  return new NodePath(ast).get('program');
}

export function statement(src, options) {
  return parse(src, options).get('body', 0);
}

export function expression(src, options) {
  return statement('(' + src + ')', options).get('expression');
}

/**
 * Injects src into template by replacing the occurrence of %s.
 */
export function parseWithTemplate(src, template) {
  return parse(template.replace('%s', stringify(src)));
}

/**
 * Default template that simply defines React and PropTypes.
 */
export const REACT_TEMPLATE = [
  'var React = require("React");',
  'var PropTypes = React.PropTypes;',
  'var {PropTypes: OtherPropTypes} = require("React");',
  '%s;',
].join('\n');

export const MODULE_TEMPLATE = [
  'var React = require("React");',
  'var PropTypes = React.PropTypes;',
  'var Component = React.createClass(%s);',
  'module.exports = Component',
].join('\n');

/**
 * Importer that doesn't resolve any values
 */
export function noopImporter() {
  return null;
}

/**
 * Builds an importer where the keys are import paths and the values are AST nodes
 */
export function makeMockImporter(mocks = {}) {
  return path => {
    const source = path.node.source.value;
    return mocks[source];
  };
}
<|endoftext|>


<commit_before>define(function(require) {
    var Notes = require('models/notes');
    var Note = require('models/note');

    var NotesItemView = Backbone.Marionette.ItemView.extend({
        template: require('tpl!notes-item'),
        tagName: 'li',
        bindings: {
            '.author': 'owner_uuid',
            '.note': 'note',
            '.date': {
                observe: 'created',
                onGet: function(created) {
                    var year = created.getFullYear();
                    var month = created.getMonth();
                    var day = created.getDate();
                    var h = created.getHours();
                    var m = created.getMinutes();
                    var date = [year, month, day].join('/');
                    var time = [h,m].join(':');
                    return [date, time].join(' ');
                }
            }
        },
        onRender: function() {
            this.stickit();
        }

    });

    var View = Backbone.Marionette.CompositeView.extend({
        template: require('tpl!notes'),

        itemView: NotesItemView,

        itemViewContainer: 'ul',

        events: {
            'click button': 'saveNote'
        },

        saveNote: function() {
            var self = this;
            var noteText = this.$('textarea').val();
            var note = new Note({
                item_uuid: this.collection.item_uuid,
                note: noteText
            });
            note.save(null, {
                success: function() {
                    self.$('textarea').val('');
                    self.collection.fetch();
                }
            });
        },

        initialize: function(options) {
            if (! options.itemUuid) {
                throw new TypeError('options.itemUuid required for notes');
            }

            this.collection = new Notes();
            this.collection.item_uuid = options.itemUuid;
            this.collection.fetch();
        }
    });

    return View;
});<commit_msg>ADMINUI-1064 Show Usernames<commit_after>define(function(require) {
    var Notes = require('models/notes');
    var Note = require('models/note');
    var User = require('models/user');

    var NotesItemView = Backbone.Marionette.ItemView.extend({
        template: require('tpl!notes-item'),
        tagName: 'li',
        initialize: function() {
            this.user = new User({uuid: this.model.get('owner_uuid')});
            this.user.fetch();
        },
        userBindings: {
            '.author': {
                observe: ['cn', 'sn'],
                onGet: function(values) {
                    return values.join(' ');
                }
            }
        },
        noteBindings: {
            '.note': 'note',
            '.date': {
                observe: 'created',
                onGet: function(created) {
                    var year = created.getFullYear();
                    var month = created.getMonth();
                    var day = created.getDate();
                    var h = created.getHours();
                    var m = created.getMinutes();
                    var date = [year, month, day].join('/');
                    var time = [h,m].join(':');
                    return [date, time].join(' ');
                }
            }
        },
        onRender: function() {
            this.stickit(this.model, this.noteBindings);
            this.stickit(this.user, this.userBindings);
        }

    });

    var View = Backbone.Marionette.CompositeView.extend({
        template: require('tpl!notes'),

        itemView: NotesItemView,

        itemViewContainer: 'ul',

        events: {
            'click button': 'saveNote'
        },

        saveNote: function() {
            var self = this;
            var noteText = this.$('textarea').val();
            var note = new Note({
                item_uuid: this.collection.item_uuid,
                note: noteText
            });
            note.save(null, {
                success: function() {
                    self.$('textarea').val('');
                    self.collection.fetch();
                }
            });
        },

        initialize: function(options) {
            if (! options.itemUuid) {
                throw new TypeError('options.itemUuid required for notes');
            }

            this.collection = new Notes();
            this.collection.item_uuid = options.itemUuid;
            this.collection.fetch();
        }
    });

    return View;
});<|endoftext|>


<commit_before>var RateLimiter = require('./rateLimiter');
var Queue = require('./queue');
var Notifier = require('./notifier');
var Telemeter = require('./telemetry');
var _ = require('./utility');

/*
 * Rollbar - the interface to Rollbar
 *
 * @param options
 * @param api
 * @param logger
 */
function Rollbar(options, api, logger, platform) {
  this.options = _.extend(true, {}, options);
  this.logger = logger;
  Rollbar.rateLimiter.configureGlobal(this.options);
  Rollbar.rateLimiter.setPlatformOptions(platform, this.options);
  this.queue = new Queue(Rollbar.rateLimiter, api, logger, this.options);
  this.notifier = new Notifier(this.queue, this.options);
  this.telemeter = new Telemeter(this.options);
  this.lastError = null;
}

var defaultOptions = {
  maxItems: 0,
  itemsPerMinute: 60
};

Rollbar.rateLimiter = new RateLimiter(defaultOptions);

Rollbar.prototype.global = function(options) {
  Rollbar.rateLimiter.configureGlobal(options);
  return this;
};

Rollbar.prototype.configure = function(options, payloadData) {
  this.notifier && this.notifier.configure(options);
  this.telemeter && this.telemeter.configure(options);
  var oldOptions = this.options;
  var payload = {};
  if (payloadData) {
    payload = {payload: payloadData};
  }
  this.options = _.extend(true, {}, oldOptions, options, payload);
  this.global(this.options);
  return this;
};

Rollbar.prototype.log = function(item) {
  var level = this._defaultLogLevel();
  return this._log(level, item);
};

Rollbar.prototype.debug = function(item) {
  this._log('debug', item);
};

Rollbar.prototype.info = function(item) {
  this._log('info', item);
};

Rollbar.prototype.warn = function(item) {
  this._log('warning', item);
};

Rollbar.prototype.warning = function(item) {
  this._log('warning', item);
};

Rollbar.prototype.error = function(item) {
  this._log('error', item);
};

Rollbar.prototype.critical = function(item) {
  this._log('critical', item);
};

Rollbar.prototype.wait = function(callback) {
  this.queue.wait(callback);
};

Rollbar.prototype.captureEvent = function(metadata, level) {
  return this.telemeter.captureEvent(metadata, level);
};

Rollbar.prototype.captureDomContentLoaded = function(ts) {
  return this.telemeter.captureDomContentLoaded(ts);
};

Rollbar.prototype.captureLoad = function(ts) {
  return this.telemeter.captureLoad(ts);
};

/* Internal */

Rollbar.prototype._log = function(defaultLevel, item) {
  if (this._sameAsLastError(item)) {
    if (item.callback) {
      item.callback();
    }
    return;
  }
  try {
    var callback = null;
    if (item.callback) {
      callback = item.callback;
      delete item.callback;
    }
    item.level = item.level || defaultLevel;
    item.telemetryEvents = this.telemeter.copyEvents();
    this.telemeter._captureRollbarItem(item);
    this.notifier.log(item, callback);
  } catch (e) {
    this.logger.error(e)
  }
};

Rollbar.prototype._defaultLogLevel = function() {
  return this.options.logLevel || 'debug';
};

Rollbar.prototype._sameAsLastError = function(item) {
  if (this.lastError && this.lastError === item.err) {
    return true;
  }
  this.lastError = item.err;
  return false;
};

module.exports = Rollbar;
<commit_msg>Include current item in telemetry queue<commit_after>var RateLimiter = require('./rateLimiter');
var Queue = require('./queue');
var Notifier = require('./notifier');
var Telemeter = require('./telemetry');
var _ = require('./utility');

/*
 * Rollbar - the interface to Rollbar
 *
 * @param options
 * @param api
 * @param logger
 */
function Rollbar(options, api, logger, platform) {
  this.options = _.extend(true, {}, options);
  this.logger = logger;
  Rollbar.rateLimiter.configureGlobal(this.options);
  Rollbar.rateLimiter.setPlatformOptions(platform, this.options);
  this.queue = new Queue(Rollbar.rateLimiter, api, logger, this.options);
  this.notifier = new Notifier(this.queue, this.options);
  this.telemeter = new Telemeter(this.options);
  this.lastError = null;
}

var defaultOptions = {
  maxItems: 0,
  itemsPerMinute: 60
};

Rollbar.rateLimiter = new RateLimiter(defaultOptions);

Rollbar.prototype.global = function(options) {
  Rollbar.rateLimiter.configureGlobal(options);
  return this;
};

Rollbar.prototype.configure = function(options, payloadData) {
  this.notifier && this.notifier.configure(options);
  this.telemeter && this.telemeter.configure(options);
  var oldOptions = this.options;
  var payload = {};
  if (payloadData) {
    payload = {payload: payloadData};
  }
  this.options = _.extend(true, {}, oldOptions, options, payload);
  this.global(this.options);
  return this;
};

Rollbar.prototype.log = function(item) {
  var level = this._defaultLogLevel();
  return this._log(level, item);
};

Rollbar.prototype.debug = function(item) {
  this._log('debug', item);
};

Rollbar.prototype.info = function(item) {
  this._log('info', item);
};

Rollbar.prototype.warn = function(item) {
  this._log('warning', item);
};

Rollbar.prototype.warning = function(item) {
  this._log('warning', item);
};

Rollbar.prototype.error = function(item) {
  this._log('error', item);
};

Rollbar.prototype.critical = function(item) {
  this._log('critical', item);
};

Rollbar.prototype.wait = function(callback) {
  this.queue.wait(callback);
};

Rollbar.prototype.captureEvent = function(metadata, level) {
  return this.telemeter.captureEvent(metadata, level);
};

Rollbar.prototype.captureDomContentLoaded = function(ts) {
  return this.telemeter.captureDomContentLoaded(ts);
};

Rollbar.prototype.captureLoad = function(ts) {
  return this.telemeter.captureLoad(ts);
};

/* Internal */

Rollbar.prototype._log = function(defaultLevel, item) {
  if (this._sameAsLastError(item)) {
    if (item.callback) {
      item.callback();
    }
    return;
  }
  try {
    var callback = null;
    if (item.callback) {
      callback = item.callback;
      delete item.callback;
    }
    item.level = item.level || defaultLevel;
    this.telemeter._captureRollbarItem(item);
    item.telemetryEvents = this.telemeter.copyEvents();
    this.notifier.log(item, callback);
  } catch (e) {
    this.logger.error(e)
  }
};

Rollbar.prototype._defaultLogLevel = function() {
  return this.options.logLevel || 'debug';
};

Rollbar.prototype._sameAsLastError = function(item) {
  if (this.lastError && this.lastError === item.err) {
    return true;
  }
  this.lastError = item.err;
  return false;
};

module.exports = Rollbar;
<|endoftext|>


<commit_before>var t = TrelloPowerUp.iframe();

t.render(function(){
    populateForm();
    t.sizeTo('#content');
});

var populateForm = function() {
    var members = {};
    return t.board('all')
    .then(function(board) {
        members = board.members;
        console.log(members);
        console.dir(members);
        UMTrello.populateSelectListBasedOnData('idsReporter', members, 'Select a Reporter', function(member) {
            return {
                name: member.fullName,
                value: member.id
            };
        });
        UMTrello.populateSelectListBasedOnData('idsAssignee', members, 'Select an Assignee', function(member) {
            return {
                name: member.fullName,
                value: member.id
            };
        });
        return t.get('card', 'shared', UMTrello.constants.data.ids, {})
        .then(function(data) {
            updateFormState(data);
        });
    });
};

var updateFormState = function(data) {
    document.getElementById('idsWhat').value = data.what ? data.what : '';
    document.getElementById('idsReporter').value = data.reporter ? data.reporter : 0;
    document.getElementById('idsAssignee').value = data.assignee ? data.assignee : 0;
};

var handleIDSSave = function (e) {
    UMTrello.disableButton('updateIDS');
    UMTrello.disableButton('deleteIDS');
    var data = {
        reporter: UMTrello.selectListSelectedValue('idsReporter'),
        assignee: UMTrello.selectListSelectedValue('idsAssignee'),
        what: document.getElementById('idsWhat').value
    };
    return t.set('card', 'shared', UMTrello.constants.data.ids, data)
    .then(function() {
        UMTrello.enableButton('updateIDS');
        UMTrello.enableButton('deleteIDS');
    });
};

var handleIDSDelete = function (e) {
    UMTrello.disableButton('updateIDS');
    UMTrello.disableButton('deleteIDS');
    return t.remove('card', 'shared', UMTrello.constants.data.ids)
    .then(function() {
        t.closePopup();
    });
};

<commit_msg>Updating IDS popup handling<commit_after>var t = TrelloPowerUp.iframe();

t.render(function(){
    populateForm();
    t.sizeTo('#content');
});

var populateForm = function() {
    var members = {};
    return t.board('all')
    .then(function(board) {
        members = board.members;
        console.log(members);
        console.dir(members);
        UMTrello.populateSelectListBasedOnData('idsReporter', members, 'Select a Reporter', function(member) {
            return {
                name: member.fullName,
                value: member.id
            };
        });
        UMTrello.populateSelectListBasedOnData('idsAssignee', members, 'Select an Assignee', function(member) {
            return {
                name: member.fullName,
                value: member.id
            };
        });
        return t.get('card', 'shared', UMTrello.constants.data.ids, {})
        .then(function(data) {
            updateFormState(data);
        });
    });
};

var updateFormState = function(data) {
    document.getElementById('idsWhat').value = data.what ? data.what : '';
    document.getElementById('idsReporter').value = data.reporter ? data.reporter : 0;
    document.getElementById('idsAssignee').value = data.assignee ? data.assignee : 0;
};

var handleIDSSave = function (e) {
    UMTrello.disableButton('updateIDS');
    UMTrello.disableButton('deleteIDS');
    var data = {
        reporter: UMTrello.selectListSelectedValue('idsReporter'),
        assignee: UMTrello.selectListSelectedValue('idsAssignee'),
        what: document.getElementById('idsWhat').value
    };
    return t.set('card', 'shared', UMTrello.constants.data.ids, data)
    .then(function() {
        t.closePopup();
    });
};

var handleIDSDelete = function (e) {
    UMTrello.disableButton('updateIDS');
    UMTrello.disableButton('deleteIDS');
    return t.remove('card', 'shared', UMTrello.constants.data.ids)
    .then(function() {
        t.closePopup();
    });
};

<|endoftext|>


<commit_before>/**
 * @flow
 */

export type EnvironmentVar = {
  name: string,
  value: string,
};
export type Environment = EnvironmentVar[];

export type EnvironmentVarExport = {
  val: string,
  scope?: string,
  exclusive?: boolean,
  __BUILT_IN_DO_NOT_USE_OR_YOU_WILL_BE_PIPd?: boolean,
};

/**
 * Describes build.
 */
export type Build = {
  /** Unique identifier */
  id: string,

  /** Build name */
  name: string,

  /** Build version */
  version: string,

  /** Command which is needed to execute build */
  command: ?(string[]),

  /** Environment exported by built. */
  exportedEnv: {[name: string]: EnvironmentVarExport},

  /**
   * Path tof the source tree relative to sandbox root.
   *
   * That's where sources are located but not necessary the location where the
   * build is executed as build process (or some other process) can relocate sources before the build.
   */
  sourcePath: string,

  /**
   * If build mutates its own sourcePath.
   *
   * Builder must handle that case somehow, probably by copying sourcePath into
   * some temp location and doing a build from there.
   */
  mutatesSourcePath: boolean,

  /**
   * If build should be persisted in store.
   *
   * Builds from released versions of packages should be persisted in store as
   * they don't change at all. On the other side builds from dev sources
   * shouldn't be persisted.
   */
  shouldBePersisted: boolean,

  /**
   * Set of dependencies which must be build/installed before this build can
   * happen
   */
  dependencies: Build[],

  /**
   * A list of errors found in build definitions.
   */
  errors: {message: string}[],
};

/**
 * Build configuration.
 */
export type BuildConfig = {
  /**
   * Path to the store used for a build.
   */
  storePath: string,

  /**
   * Path to a sandbox root.
   */
  sandboxPath: string,

  /**
   * Generate path where sources of the builds are located.
   */
  getSourcePath: (build: Build, ...segments: string[]) => string,

  /**
   * Generate path from where the build executes.
   */
  getRootPath: (build: Build, ...segments: string[]) => string,

  /**
   * Generate path where build artefacts should be placed.
   */
  getBuildPath: (build: Build, ...segments: string[]) => string,

  /**
   * Generate path where installation artefacts should be placed.
   */
  getInstallPath: (build: Build, ...segments: string[]) => string,

  /**
   * Generate path where finalized installation artefacts should be placed.
   *
   * Installation and final installation path are different because we want to
   * do atomic installs (possible by buiilding in one location and then mv'ing
   * to another, final location).
   */
  getFinalInstallPath: (build: Build, ...segments: string[]) => string,
};

/**
 * A build root together with a global env.
 *
 * Note that usually builds do not exist outside of build sandboxes as their own
 * identities a made dependent on a global env of the sandbox.
 */
export type BuildSandbox = {
  env: Environment,
  root: Build,
};

/**
 * Process which accepts build and a corresponding config and produces a build.
 */
export type Builder = (BuildSandbox, BuildConfig) => Promise<void>;

/**
 * BFS for build dep graph.
 */
export function traverse(build: Build, f: (Build) => void) {
  const seen = new Set();
  const queue = [build];
  while (queue.length > 0) {
    const cur = queue.shift();
    if (seen.has(cur.id)) {
      continue;
    }
    f(cur);
    seen.add(cur.id);
    queue.push(...cur.dependencies);
  }
}

export function traverseDeepFirst(build: Build, f: (Build) => void) {
  const seen = new Set();
  function traverse(build) {
    if (seen.has(build.id)) {
      return;
    }
    seen.add(build.id);
    for (const dep of build.dependencies) {
      traverse(dep);
    }
    f(build);
  }
  traverse(build);
}

/**
 * Collect all transitive dependendencies for a `build`.
 */
export function collectTransitiveDependencies(build: Build): Build[] {
  const dependencies = [];
  traverse(build, cur => {
    // Skip the root build
    if (cur !== build) {
      dependencies.push(cur);
    }
  });
  return dependencies;
}

/**
 * Topological fold build dependency graph to a value `V`.
 *
 * The fold function is called with a list of values computed for dependencies
 * in topological order and a build itself.
 *
 * Note that value is computed only once per build (even if it happen to be
 * depended on if a few places) and then memoized.
 */
export function topologicalFold<V>(build: Build, f: (V[], Build) => V): V {
  return topologicalFoldImpl(build, f, new Map(), value => value);
}

function topologicalFoldImpl<V>(
  build: Build,
  f: (V[], Build) => V,
  memoized: Map<string, V>,
  onBuild: (V, Build) => *,
): V {
  const depValues = [];
  const toVisit = new Set(build.dependencies.map(dep => dep.id));
  for (let i = 0; i < build.dependencies.length; i++) {
    const dep = build.dependencies[i];
    if (toVisit.delete(dep.id)) {
      let value = memoized.get(dep.id);
      if (value == null) {
        value = topologicalFoldImpl(dep, f, memoized, (value, dep) => {
          if (toVisit.delete(dep.id)) {
            depValues.push(value);
          }
          return onBuild(value, dep);
        });
        memoized.set(dep.id, value);
      }
      depValues.push(value);
    }
  }
  return onBuild(f(depValues, build), build);
}
<commit_msg>Fix collectTransitiveDependencies to return deps sorted in topo order<commit_after>/**
 * @flow
 */

export type EnvironmentVar = {
  name: string,
  value: string,
};
export type Environment = EnvironmentVar[];

export type EnvironmentVarExport = {
  val: string,
  scope?: string,
  exclusive?: boolean,
  __BUILT_IN_DO_NOT_USE_OR_YOU_WILL_BE_PIPd?: boolean,
};

/**
 * Describes build.
 */
export type Build = {
  /** Unique identifier */
  id: string,

  /** Build name */
  name: string,

  /** Build version */
  version: string,

  /** Command which is needed to execute build */
  command: ?(string[]),

  /** Environment exported by built. */
  exportedEnv: {[name: string]: EnvironmentVarExport},

  /**
   * Path tof the source tree relative to sandbox root.
   *
   * That's where sources are located but not necessary the location where the
   * build is executed as build process (or some other process) can relocate sources before the build.
   */
  sourcePath: string,

  /**
   * If build mutates its own sourcePath.
   *
   * Builder must handle that case somehow, probably by copying sourcePath into
   * some temp location and doing a build from there.
   */
  mutatesSourcePath: boolean,

  /**
   * If build should be persisted in store.
   *
   * Builds from released versions of packages should be persisted in store as
   * they don't change at all. On the other side builds from dev sources
   * shouldn't be persisted.
   */
  shouldBePersisted: boolean,

  /**
   * Set of dependencies which must be build/installed before this build can
   * happen
   */
  dependencies: Build[],

  /**
   * A list of errors found in build definitions.
   */
  errors: {message: string}[],
};

/**
 * Build configuration.
 */
export type BuildConfig = {
  /**
   * Path to the store used for a build.
   */
  storePath: string,

  /**
   * Path to a sandbox root.
   */
  sandboxPath: string,

  /**
   * Generate path where sources of the builds are located.
   */
  getSourcePath: (build: Build, ...segments: string[]) => string,

  /**
   * Generate path from where the build executes.
   */
  getRootPath: (build: Build, ...segments: string[]) => string,

  /**
   * Generate path where build artefacts should be placed.
   */
  getBuildPath: (build: Build, ...segments: string[]) => string,

  /**
   * Generate path where installation artefacts should be placed.
   */
  getInstallPath: (build: Build, ...segments: string[]) => string,

  /**
   * Generate path where finalized installation artefacts should be placed.
   *
   * Installation and final installation path are different because we want to
   * do atomic installs (possible by buiilding in one location and then mv'ing
   * to another, final location).
   */
  getFinalInstallPath: (build: Build, ...segments: string[]) => string,
};

/**
 * A build root together with a global env.
 *
 * Note that usually builds do not exist outside of build sandboxes as their own
 * identities a made dependent on a global env of the sandbox.
 */
export type BuildSandbox = {
  env: Environment,
  root: Build,
};

/**
 * Process which accepts build and a corresponding config and produces a build.
 */
export type Builder = (BuildSandbox, BuildConfig) => Promise<void>;

/**
 * BFS for build dep graph.
 */
export function traverse(build: Build, f: (Build) => void) {
  const seen = new Set();
  const queue = [build];
  while (queue.length > 0) {
    const cur = queue.shift();
    if (seen.has(cur.id)) {
      continue;
    }
    f(cur);
    seen.add(cur.id);
    queue.push(...cur.dependencies);
  }
}

export function traverseDeepFirst(build: Build, f: (Build) => void) {
  const seen = new Set();
  function traverse(build) {
    if (seen.has(build.id)) {
      return;
    }
    seen.add(build.id);
    for (const dep of build.dependencies) {
      traverse(dep);
    }
    f(build);
  }
  traverse(build);
}

/**
 * Collect all transitive dependendencies for a `build`.
 */
export function collectTransitiveDependencies(build: Build): Build[] {
  const dependencies = [];
  traverseDeepFirst(build, cur => {
    // Skip the root build
    if (cur !== build) {
      dependencies.push(cur);
    }
  });
  dependencies.reverse();
  return dependencies;
}

/**
 * Topological fold build dependency graph to a value `V`.
 *
 * The fold function is called with a list of values computed for dependencies
 * in topological order and a build itself.
 *
 * Note that value is computed only once per build (even if it happen to be
 * depended on if a few places) and then memoized.
 */
export function topologicalFold<V>(build: Build, f: (V[], Build) => V): V {
  return topologicalFoldImpl(build, f, new Map(), value => value);
}

function topologicalFoldImpl<V>(
  build: Build,
  f: (V[], Build) => V,
  memoized: Map<string, V>,
  onBuild: (V, Build) => *,
): V {
  const depValues = [];
  const toVisit = new Set(build.dependencies.map(dep => dep.id));
  for (let i = 0; i < build.dependencies.length; i++) {
    const dep = build.dependencies[i];
    if (toVisit.delete(dep.id)) {
      let value = memoized.get(dep.id);
      if (value == null) {
        value = topologicalFoldImpl(dep, f, memoized, (value, dep) => {
          if (toVisit.delete(dep.id)) {
            depValues.push(value);
          }
          return onBuild(value, dep);
        });
        memoized.set(dep.id, value);
      }
      depValues.push(value);
    }
  }
  return onBuild(f(depValues, build), build);
}
<|endoftext|>