<commit_before>var chai = require('chai'),
  should = chai.should(),
  validator = require('validator'),
  _ = require('underscore'),
  express = require('express'),
  app = express(),
  sinon = require("sinon"),
  sinonChai = require("sinon-chai"),
  request = require('supertest'),
  proxyquire = require('proxyquire'),
  eventStoreClient = {
    streams: {
      post: sinon.stub()
    },
    projection: {
      getState: sinon.stub()
    }
  },
  hypermediaResponseStub = {
    inboxes: {
      POST: sinon.stub()
    }
  },
  inboxAdded = {
    validate: sinon.stub(),
    create: sinon.stub()
  },
  sanitizer = {
    sanitize: sinon.stub()
  },
  translator = {
    translatePush: sinon.stub()
  },
  controller = proxyquire('../../api/inboxesController', {
    './hypermediaResponse': hypermediaResponseStub,
    './sanitizer': sanitizer,
    './events/inboxAdded': inboxAdded,
    './helpers/eventStoreClient': eventStoreClient,
    './translators/githubTranslator': translator
  });

chai.use(sinonChai);
chai.config.includeStack = true;

controller.init(app);

var getInbox = function(path, shouldBehaveThusly) {
  request(app)
    .get(path)
    .end(shouldBehaveThusly);
}

var postInboxCreate = function(payload, shouldBehaveThusly, contentType) {
  if (!contentType) {
    contentType = 'application/json';
  }
  request(app)
    .post('/api/inboxes')
    .send(JSON.stringify(payload))
    .type(contentType)
    .end(shouldBehaveThusly);
};

var postInbox = function(payload, shouldBehaveThusly, contentType, inboxUuid, xGithubEventValue) {
  if (!contentType) {
    contentType = 'application/json';
  }
  request(app)
    .post('/api/inboxes/' + inboxUuid)
    .set('x-github-event', xGithubEventValue || 'push')
    .send(JSON.stringify(payload))
    .type(contentType)
    .end(shouldBehaveThusly);
};

describe('inboxesController', function() {

  describe('when creating an inbox', function() {

    var digestId = 'e9be4a71-f6ca-4f02-b431-d74489dee5d0';
    var payload = {
      name: 'His name was Robert Paulson',
      digestId: digestId,
      family: 'GitHub'
    };

    describe('with an unsupported or missing Content-Type header', function() {
      var payload = {};
      it('should reject request and return a 415 status code.', function(done) {
        postInboxCreate(payload, function(err, res) {
          res.statusCode.should.equal(415);
          done();
        }, 'application/jackson');
      });

      it('it should reject the request and explain that only application/json is accepted.', function(done) {
        postInboxCreate(payload, function(err, res) {
          res.text.should.equal('When creating an inbox, you must send a Content-Type: application/json header.');
          done();
        }, 'application/jackson');
      });
    });

    describe('with a valid payload', function() {
      var inboxId = '53d8c6ac-37f4-453f-b252-cb2d93c18fa7';

      var protocol = 'http';
      var host = 'localhost';

      var hypermediaResponse = {
        "_links": {
          "self": {
            "href": protocol + "://" + host + "/api/inboxes/" + inboxId
          }
        }
      };

      var inboxAddedEvent = {
        eventType: 'InboxAdded',
        eventId: 'a4cfd6f3-3cb4-4504-ae52-cc8d9fcb8818',
        data: {
          digestId: digestId,
          inboxId: inboxId,
          family: 'GitHub',
          name: 'some name',
          url: 'http://www.someURL.com'
        }
      };

      before(function() {
        sanitizer.sanitize.returns([]);
        inboxAdded.validate.returns([]);
        inboxAdded.create.returns(inboxAddedEvent);
        hypermediaResponseStub.inboxes.POST.returns(hypermediaResponse);
      })

      beforeEach(function() {
        eventStoreClient.streams.post.callsArgWith(1, null, "unused response");
      });

      it('should clean the name field for illegal content', function(done) {
        postInboxCreate(payload, function() {
          sanitizer.sanitize.should.have.been.calledWith('inbox', payload, ['name']);
          done();
        });
      });

      it('should validate the payload against an inboxAdded schema', function(done) {
        postInboxCreate(payload, function() {
          inboxAdded.validate.should.have.been.calledWith(payload);
          done();
        });
      })

      it('it should have a response Content-Type of hal+json', function(done) {
        postInboxCreate(payload, function(err, res) {
          res.get('Content-Type').should.equal('application/hal+json; charset=utf-8');
          done();
        });
      });

      it('it should use proper arguments when creating hypermedia.', function(done) {
        postInboxCreate(payload, function(err, res) {
          hypermediaResponseStub.inboxes.POST.should.have.been.calledWith(protocol, sinon.match.any, inboxAddedEvent.data.inboxId);
          done();
        });
      });

      it('it should have a response code of 201 created', function(done) {
        postInboxCreate(payload, function(err, res) {
          res.status.should.equal(201);
          done();
        });
      });

      it('it should set the Location response header to the newly created digest', function(done) {
        postInboxCreate(payload, function(err, res) {
          res.get('Location').should.equal(hypermediaResponse._links.self.href);
          done();
        });
      });
    });

    describe('and failures occur', function() {

      before(function() {
        eventStoreClient.streams.post.callsArgWith(1, 'Houston, we have a problem', null);
        sanitizer.sanitize.returns('Houston, we have a problem');
      });

      it('when posting to eventstore it should send back an apprpriate error response', function(done) {
        postInboxCreate(payload, function(err, res) {
          res.body.errors.should.equal('We had an internal problem. Please retry your request. Error: Houston, we have a problem');
          done();
        });
      });

      it('when santize returns an error it gives an appropriate error message', function(done) {
        postInboxCreate(payload, function(err, res) {
          res.body.errors.should.equal('Houston, we have a problem');
          done();
        });
      });

      it('when santize returns an error it gives an appropriate response code', function(done) {
        postInboxCreate(payload, function(err, res) {
          res.statusCode.should.equal(400);
          done();
        });
      });
    });
  });

  describe('when posting to an inbox', function() {
    var inboxId = 'c347948f-e1d0-4cd7-9341-f0f6ef5289bf';
    var digestId = 'e9be4a71-f6ca-4f02-b431-d74489dee5d0';

    var inboxPayload = {};

    var translatorEvent = {
      eventId: 'b0d65208-2afc-43f0-8926-6b20026ab1eb',
      eventType: 'GitHubCommitReceived',
      data: {},
      metadata: {
        digestId: digestId
      }
    };

    before(function() {
      translator.translatePush.returns(translatorEvent);
      translatorEvent = JSON.stringify(translatorEvent);
    });

    beforeEach(function() {
      eventStoreClient.projection.getState.callsArgWith(1, null, {
        body: JSON.stringify({
          digestId: digestId
        }),
        statusCode: 200
      });
    });

    it('it should call the translator with the correct params', function(done) {
      postInbox(inboxPayload, function(err, res) {
        translator.translatePush.should.have.been.calledWith(inboxPayload, digestId)
        done();
      }, null, inboxId);
    });

    it('it should post to the eventStoreClient with the correct params', function(done) {
      postInbox(inboxPayload, function(err, res) {
        var eventStoreClientParam1 = {
          name: 'inboxCommits-' + inboxId,
          events: translatorEvent
        };
        eventStoreClient.streams.post.should.have.been.calledWith(eventStoreClientParam1, sinon.match.any);
        done();
      });
    });

    it('it should have a response Content-Type of hal+json', function(done) {

      postInbox(inboxPayload, function(err, res) {
        res.get('Content-Type').should.equal('application/hal+json; charset=utf-8');
        done();
      }, null, inboxId);
    });

    it('it should have an appropriate response message', function(done) {
      postInbox(inboxPayload, function(err, res) {
        res.body.message.should.equal('Your push event has been queued to be added to CommitStream.');
        done();
      }, null, inboxId);
    })

    // it('it should have an x-github-event header with a value of push', function(done) {
    //   done();
    // });

    describe('without the x-github-event header', function() {
      it('it should provide an appropriate response', function(done) {

        var postInboxWithoutXGithubEvent = function(shouldBehaveThusly) {
          var inboxId = 'c347948f-e1d0-4cd7-9341-f0f6ef5289bf';
          var digestId = 'e9be4a71-f6ca-4f02-b431-d74489dee5d0';
          var payload = {
            digestId: digestId
          };

          request(app)
            .post('/api/inboxes/' + inboxId)
            .send(JSON.stringify(payload))
            .type('application/json')
            .end(shouldBehaveThusly);
        }

        postInboxWithoutXGithubEvent(function(err, res) {
          res.body.message.should.equal('Unknown event type.');
          done();
        });
      });
    });
  });

  describe('when retrieving information about an inbox', function() {
    var inboxId = 'c347948f-e1d0-4cd7-9341-f0f6ef5289bf';
    var digestId = 'e9be4a71-f6ca-4f02-b431-d74489dee5d0';

    describe('with an invalid, non-uuid inboxes identifier', function() {
      function get(shouldBehaveThusly) {
        getInbox('/api/inboxes/not_a_uuid', shouldBehaveThusly);
      }

      it('it returns a 400 status code', function(done) {
        get(function(err, res) {
          res.statusCode.should.equal(400);
          done();
        });
      });

      it('it returns a meaningful error message', function(done) {
        get(function(err, res) {
          res.text.should.equal('The value "not_a_uuid" is not recognized as a valid inbox identifier.');
          done();
        });
      });
    });

    describe('with a valid, uuid inbox identifier', function() {

      beforeEach(function() {
        eventStoreClient.projection.getState.callsArgWith(1, null, {
          body: JSON.stringify({
            digestId: digestId
          }),
          statusCode: 200
        });
      });

      function get(shouldBehaveThusly) {
        getInbox('/api/inboxes/' + inboxId, shouldBehaveThusly);
      }

      it('calls eventStore.projection.getState with correct parameters', function(done) {
        get(function(err, res) {
          eventStoreClient.projection.getState.should.have.been.calledWith({
            name: sinon.match.any,
            partition: 'inbox-' + inboxId
          }, sinon.match.any);
          done();
        });
      });

      it('it returns a 200 status code', function(done) {
        get(function(err, res) {
          res.statusCode.should.equal(200);
          done();
        });
      });

      it('returns a Content-Type of application/hal+json', function(done) {
        get(function(err, res) {
          res.get('Content-Type').should.equal('application/hal+json; charset=utf-8');
          done();
        });
      });

    });

    describe('with a valid, uuid that does not match a real inbox', function() {

      beforeEach(function() {
        eventStoreClient.projection.getState.callsArgWith(1, null, {
          body: ''
        });
      });

      function get(shouldBehaveThusly) {
        getInbox('/api/inboxes/' + inboxId, shouldBehaveThusly);
      }

      it('calls eventStore.projection.getState with correct parameters', function(done) {
        get(function(err, res) {
          eventStoreClient.projection.getState.should.have.been.calledWith({
            name: sinon.match.any,
            partition: 'inbox-' + inboxId
          }, sinon.match.any);
          done();
        });
      });

      it('it returns a 404 status code', function(done) {
        get(function(err, res) {
          res.statusCode.should.equal(404);
          done();
        });
      });

      it('returns a Content-Type of application/json', function(done) {
        get(function(err, res) {
          res.get('Content-Type').should.equal('application/json; charset=utf-8');
          done();
        });
      });

      it('it returns a meaningful error message', function(done) {
        get(function(err, res) {
          res.text.should.equal(JSON.stringify({
            'error': 'Could not find an inbox with id ' + inboxId
          }));
          done();
        });
      });

    });

    describe('with an error returned from eventStoreClient', function() {

      beforeEach(function() {
        eventStoreClient.projection.getState.callsArgWith(1, 'Hey there is an error!', {});
      });

      function get(shouldBehaveThusly) {
        getInbox('/api/inboxes/' + inboxId, shouldBehaveThusly);
      }

      it('calls eventStore.projection.getState with correct parameters', function(done) {
        get(function(err, res) {
          eventStoreClient.projection.getState.should.have.been.calledWith({
            name: sinon.match.any,
            partition: 'inbox-' + inboxId
          }, sinon.match.any);
          done();
        });
      });

      it('it returns a 500 status code', function(done) {
        get(function(err, res) {
          res.statusCode.should.equal(500);
          done();
        });
      });

      it('returns a Content-Type of application/json', function(done) {
        get(function(err, res) {
          res.get('Content-Type').should.equal('application/json; charset=utf-8');
          done();
        });
      });

      it('it returns a meaningful error message', function(done) {
        get(function(err, res) {
          res.text.should.equal(JSON.stringify({
            'error': 'There was an internal error when trying to process your request'
          }));
          done();
        });
      });

    });

  });
  it('it should have a response Content-Type of hal+json', function(done) {
    // return false;
    done();
  });

});<commit_msg>Pull sanitize tests into their own describe.<commit_after>var chai = require('chai'),
  should = chai.should(),
  validator = require('validator'),
  _ = require('underscore'),
  express = require('express'),
  app = express(),
  sinon = require("sinon"),
  sinonChai = require("sinon-chai"),
  request = require('supertest'),
  proxyquire = require('proxyquire'),
  eventStoreClient = {
    streams: {
      post: sinon.stub()
    },
    projection: {
      getState: sinon.stub()
    }
  },
  hypermediaResponseStub = {
    inboxes: {
      POST: sinon.stub()
    }
  },
  inboxAdded = {
    validate: sinon.stub(),
    create: sinon.stub()
  },
  sanitizer = {
    sanitize: sinon.stub()
  },
  translator = {
    translatePush: sinon.stub()
  },
  controller = proxyquire('../../api/inboxesController', {
    './hypermediaResponse': hypermediaResponseStub,
    './sanitizer': sanitizer,
    './events/inboxAdded': inboxAdded,
    './helpers/eventStoreClient': eventStoreClient,
    './translators/githubTranslator': translator
  });

chai.use(sinonChai);
chai.config.includeStack = true;

controller.init(app);

var getInbox = function(path, shouldBehaveThusly) {
  request(app)
    .get(path)
    .end(shouldBehaveThusly);
}

var postInboxCreate = function(payload, shouldBehaveThusly, contentType) {
  if (!contentType) {
    contentType = 'application/json';
  }
  request(app)
    .post('/api/inboxes')
    .send(JSON.stringify(payload))
    .type(contentType)
    .end(shouldBehaveThusly);
};

var postInbox = function(payload, shouldBehaveThusly, contentType, inboxUuid, xGithubEventValue) {
  if (!contentType) {
    contentType = 'application/json';
  }
  request(app)
    .post('/api/inboxes/' + inboxUuid)
    .set('x-github-event', xGithubEventValue || 'push')
    .send(JSON.stringify(payload))
    .type(contentType)
    .end(shouldBehaveThusly);
};

describe('inboxesController', function() {

  describe('when creating an inbox', function() {

    var digestId = 'e9be4a71-f6ca-4f02-b431-d74489dee5d0';
    var payload = {
      name: 'His name was Robert Paulson',
      digestId: digestId,
      family: 'GitHub'
    };

    describe('with an unsupported or missing Content-Type header', function() {
      var payload = {};
      it('should reject request and return a 415 status code.', function(done) {
        postInboxCreate(payload, function(err, res) {
          res.statusCode.should.equal(415);
          done();
        }, 'application/jackson');
      });

      it('it should reject the request and explain that only application/json is accepted.', function(done) {
        postInboxCreate(payload, function(err, res) {
          res.text.should.equal('When creating an inbox, you must send a Content-Type: application/json header.');
          done();
        }, 'application/jackson');
      });
    });

    describe('with a valid payload', function() {
      var inboxId = '53d8c6ac-37f4-453f-b252-cb2d93c18fa7';

      var protocol = 'http';
      var host = 'localhost';

      var hypermediaResponse = {
        "_links": {
          "self": {
            "href": protocol + "://" + host + "/api/inboxes/" + inboxId
          }
        }
      };

      var inboxAddedEvent = {
        eventType: 'InboxAdded',
        eventId: 'a4cfd6f3-3cb4-4504-ae52-cc8d9fcb8818',
        data: {
          digestId: digestId,
          inboxId: inboxId,
          family: 'GitHub',
          name: 'some name',
          url: 'http://www.someURL.com'
        }
      };

      before(function() {
        sanitizer.sanitize.returns([]);
        inboxAdded.validate.returns([]);
        inboxAdded.create.returns(inboxAddedEvent);
        hypermediaResponseStub.inboxes.POST.returns(hypermediaResponse);
      })

      beforeEach(function() {
        eventStoreClient.streams.post.callsArgWith(1, null, "unused response");
      });

      it('should clean the name field for illegal content', function(done) {
        postInboxCreate(payload, function() {
          sanitizer.sanitize.should.have.been.calledWith('inbox', payload, ['name']);
          done();
        });
      });

      it('should validate the payload against an inboxAdded schema', function(done) {
        postInboxCreate(payload, function() {
          inboxAdded.validate.should.have.been.calledWith(payload);
          done();
        });
      })

      it('it should have a response Content-Type of hal+json', function(done) {
        postInboxCreate(payload, function(err, res) {
          res.get('Content-Type').should.equal('application/hal+json; charset=utf-8');
          done();
        });
      });

      it('it should use proper arguments when creating hypermedia.', function(done) {
        postInboxCreate(payload, function(err, res) {
          hypermediaResponseStub.inboxes.POST.should.have.been.calledWith(protocol, sinon.match.any, inboxAddedEvent.data.inboxId);
          done();
        });
      });

      it('it should have a response code of 201 created', function(done) {
        postInboxCreate(payload, function(err, res) {
          res.status.should.equal(201);
          done();
        });
      });

      it('it should set the Location response header to the newly created digest', function(done) {
        postInboxCreate(payload, function(err, res) {
          res.get('Location').should.equal(hypermediaResponse._links.self.href);
          done();
        });
      });
    });

    describe('and failures occur when posting to eventstore', function() {

      before(function() {
        eventStoreClient.streams.post.callsArgWith(1, 'Houston, we have a problem', null);
      });

      it('it should send back an apprpriate error response', function(done) {
        postInboxCreate(payload, function(err, res) {
          res.body.errors.should.equal('We had an internal problem. Please retry your request. Error: Houston, we have a problem');
          done();
        });
      });
    });

    describe('and santize reports an error', function() {
      before(function() {
        sanitizer.sanitize.returns('Houston, we have a problem');
      });

      it('when santize returns an error it gives an appropriate error message', function(done) {
        postInboxCreate(payload, function(err, res) {
          res.body.errors.should.equal('Houston, we have a problem');
          done();
        });
      });

      it('when santize returns an error it gives an appropriate response code', function(done) {
        postInboxCreate(payload, function(err, res) {
          res.statusCode.should.equal(400);
          done();
        });
      });
    });
  });

  describe('when posting to an inbox', function() {
    var inboxId = 'c347948f-e1d0-4cd7-9341-f0f6ef5289bf';
    var digestId = 'e9be4a71-f6ca-4f02-b431-d74489dee5d0';

    var inboxPayload = {};

    var translatorEvent = {
      eventId: 'b0d65208-2afc-43f0-8926-6b20026ab1eb',
      eventType: 'GitHubCommitReceived',
      data: {},
      metadata: {
        digestId: digestId
      }
    };

    before(function() {
      translator.translatePush.returns(translatorEvent);
      translatorEvent = JSON.stringify(translatorEvent);
    });

    beforeEach(function() {
      eventStoreClient.projection.getState.callsArgWith(1, null, {
        body: JSON.stringify({
          digestId: digestId
        }),
        statusCode: 200
      });
    });

    it('it should call the translator with the correct params', function(done) {
      postInbox(inboxPayload, function(err, res) {
        translator.translatePush.should.have.been.calledWith(inboxPayload, digestId)
        done();
      }, null, inboxId);
    });

    it('it should post to the eventStoreClient with the correct params', function(done) {
      postInbox(inboxPayload, function(err, res) {
        var eventStoreClientParam1 = {
          name: 'inboxCommits-' + inboxId,
          events: translatorEvent
        };
        eventStoreClient.streams.post.should.have.been.calledWith(eventStoreClientParam1, sinon.match.any);
        done();
      });
    });

    it('it should have a response Content-Type of hal+json', function(done) {

      postInbox(inboxPayload, function(err, res) {
        res.get('Content-Type').should.equal('application/hal+json; charset=utf-8');
        done();
      }, null, inboxId);
    });

    it('it should have an appropriate response message', function(done) {
      postInbox(inboxPayload, function(err, res) {
        res.body.message.should.equal('Your push event has been queued to be added to CommitStream.');
        done();
      }, null, inboxId);
    })

    // it('it should have an x-github-event header with a value of push', function(done) {
    //   done();
    // });

    describe('without the x-github-event header', function() {
      it('it should provide an appropriate response', function(done) {

        var postInboxWithoutXGithubEvent = function(shouldBehaveThusly) {
          var inboxId = 'c347948f-e1d0-4cd7-9341-f0f6ef5289bf';
          var digestId = 'e9be4a71-f6ca-4f02-b431-d74489dee5d0';
          var payload = {
            digestId: digestId
          };

          request(app)
            .post('/api/inboxes/' + inboxId)
            .send(JSON.stringify(payload))
            .type('application/json')
            .end(shouldBehaveThusly);
        }

        postInboxWithoutXGithubEvent(function(err, res) {
          res.body.message.should.equal('Unknown event type.');
          done();
        });
      });
    });
  });

  describe('when retrieving information about an inbox', function() {
    var inboxId = 'c347948f-e1d0-4cd7-9341-f0f6ef5289bf';
    var digestId = 'e9be4a71-f6ca-4f02-b431-d74489dee5d0';

    describe('with an invalid, non-uuid inboxes identifier', function() {
      function get(shouldBehaveThusly) {
        getInbox('/api/inboxes/not_a_uuid', shouldBehaveThusly);
      }

      it('it returns a 400 status code', function(done) {
        get(function(err, res) {
          res.statusCode.should.equal(400);
          done();
        });
      });

      it('it returns a meaningful error message', function(done) {
        get(function(err, res) {
          res.text.should.equal('The value "not_a_uuid" is not recognized as a valid inbox identifier.');
          done();
        });
      });
    });

    describe('with a valid, uuid inbox identifier', function() {

      beforeEach(function() {
        eventStoreClient.projection.getState.callsArgWith(1, null, {
          body: JSON.stringify({
            digestId: digestId
          }),
          statusCode: 200
        });
      });

      function get(shouldBehaveThusly) {
        getInbox('/api/inboxes/' + inboxId, shouldBehaveThusly);
      }

      it('calls eventStore.projection.getState with correct parameters', function(done) {
        get(function(err, res) {
          eventStoreClient.projection.getState.should.have.been.calledWith({
            name: sinon.match.any,
            partition: 'inbox-' + inboxId
          }, sinon.match.any);
          done();
        });
      });

      it('it returns a 200 status code', function(done) {
        get(function(err, res) {
          res.statusCode.should.equal(200);
          done();
        });
      });

      it('returns a Content-Type of application/hal+json', function(done) {
        get(function(err, res) {
          res.get('Content-Type').should.equal('application/hal+json; charset=utf-8');
          done();
        });
      });

    });

    describe('with a valid, uuid that does not match a real inbox', function() {

      beforeEach(function() {
        eventStoreClient.projection.getState.callsArgWith(1, null, {
          body: ''
        });
      });

      function get(shouldBehaveThusly) {
        getInbox('/api/inboxes/' + inboxId, shouldBehaveThusly);
      }

      it('calls eventStore.projection.getState with correct parameters', function(done) {
        get(function(err, res) {
          eventStoreClient.projection.getState.should.have.been.calledWith({
            name: sinon.match.any,
            partition: 'inbox-' + inboxId
          }, sinon.match.any);
          done();
        });
      });

      it('it returns a 404 status code', function(done) {
        get(function(err, res) {
          res.statusCode.should.equal(404);
          done();
        });
      });

      it('returns a Content-Type of application/json', function(done) {
        get(function(err, res) {
          res.get('Content-Type').should.equal('application/json; charset=utf-8');
          done();
        });
      });

      it('it returns a meaningful error message', function(done) {
        get(function(err, res) {
          res.text.should.equal(JSON.stringify({
            'error': 'Could not find an inbox with id ' + inboxId
          }));
          done();
        });
      });

    });

    describe('with an error returned from eventStoreClient', function() {

      beforeEach(function() {
        eventStoreClient.projection.getState.callsArgWith(1, 'Hey there is an error!', {});
      });

      function get(shouldBehaveThusly) {
        getInbox('/api/inboxes/' + inboxId, shouldBehaveThusly);
      }

      it('calls eventStore.projection.getState with correct parameters', function(done) {
        get(function(err, res) {
          eventStoreClient.projection.getState.should.have.been.calledWith({
            name: sinon.match.any,
            partition: 'inbox-' + inboxId
          }, sinon.match.any);
          done();
        });
      });

      it('it returns a 500 status code', function(done) {
        get(function(err, res) {
          res.statusCode.should.equal(500);
          done();
        });
      });

      it('returns a Content-Type of application/json', function(done) {
        get(function(err, res) {
          res.get('Content-Type').should.equal('application/json; charset=utf-8');
          done();
        });
      });

      it('it returns a meaningful error message', function(done) {
        get(function(err, res) {
          res.text.should.equal(JSON.stringify({
            'error': 'There was an internal error when trying to process your request'
          }));
          done();
        });
      });

    });

  });
  it('it should have a response Content-Type of hal+json', function(done) {
    // return false;
    done();
  });

});<|endoftext|>


<commit_before>var Lang = A.Lang;

var NEW_LINE = '\n';

var TAG_BOLD = '**';
var TAG_EMPHASIZE = '//';
var TAG_PRE = 'pre';
var TAG_ORDERED_LIST = 'ol';
var TAG_ORDEREDLIST_ITEM = '#';
var TAG_UNORDERED_LIST = 'ul';
var TAG_UNORDEREDLIST_ITEM = '*';

var REGEX_BOLD = /(?:^|\s)font-weight\s*:\s*bold\s*;?/i;
var REGEX_HEADER = /^h([1-6])$/i;
var REGEX_ITALIC = /(?:^|\s)font-style\s*:\s*italic\s*;?/i;
var REGEX_NOT_WHITESPACE = /[^\t\n\r ]/;
var REGEX_LASTCHAR_NEWLINE = /(\r?\n\s*)$/;

var SPACE = ' ';

var HTML2CreoleConvertor = A.Component.create(
	{
		NAME: 'domparsercreole',

		ATTRS: {
			data: {
				value: null,
				validator: Lang.isString
			}
		},

		EXTENDS: A.Base,

		prototype: {
			_endResult: null,

			_ulLevel: 0,

			initializer: function() {

			},

			convert: function(data) {
				var instance = this;

				if (data) {
					this.set('data', data);
				} else {
					data = this.get('data');
				}

				var node = A.config.doc.createElement('div');
				node.innerHTML = data;

				instance._handle(node);

				var endResult = instance._endResult.join('');

				instance._endResult = null;

				return endResult;
			},

			_isAllWS: function(node) {
				return !(REGEX_NOT_WHITESPACE.test(node.data));
			},

			_isIgnorable: function(node) {
				var instance = this;

				var nodeType = node.nodeType;

				return (nodeType == 8) ||
					((nodeType == 3) && instance._isAllWS(node));
			},

			_isLastItemNewLine: function(node) {
				var instance = this;

				var endResult = instance._endResult;

				return (endResult && REGEX_LASTCHAR_NEWLINE.test(endResult.slice(-1)));
			},

			_handle: function(node) {
				var instance = this;

				var child, children, data, i, listTagsIn, listTagsOut,
					length, stylesTagsIn, stylesTagsOut, pushTagList;

				if (!Lang.isArray(instance._endResult)) {
					instance._endResult = [];
				}

				children = node.childNodes;
				pushTagList = instance._pushTagList;
				length = children.length;

				for (i = 0; i < length; i++) {
					listTagsIn = [];
					listTagsOut = [];

					stylesTagsIn = [];
					stylesTagsOut = [];

					child = children[i];

					if (instance._isIgnorable(child)) {
						continue;
					}

					instance._handleElementStart(child, listTagsIn, listTagsOut);
					instance._handleStyles(child, stylesTagsIn, stylesTagsOut);

					pushTagList.call(instance, listTagsIn);
					pushTagList.call(instance, stylesTagsIn);

					instance._handle(child);

					instance._handleElementEnd(child, listTagsIn, listTagsOut);

					pushTagList.call(instance, stylesTagsOut.reverse());
					pushTagList.call(instance, listTagsOut);
				}

				data = node.data;

				instance._handleData(data, node);
			},

			_handleData: function(data, element) {
				var instance = this;

				if (Lang.isValue(data)) {
					instance._endResult.push(data);

					var parentNode = element.parentNode;

					if (parentNode) {
						var parentTagName = parentNode.tagName;

						if (parentTagName) {
							parentTagName = parentTagName.toLowerCase();
						}
					}
				}
			},

			_handleElementStart: function(element, listTagsIn, listTagsOut) {
				var instance = this;

				var tagName = element.tagName;
				var params;

				if (tagName) {
					tagName = tagName.toLowerCase();

					if (tagName == 'p') {
						instance._handleParagraph(element, listTagsIn, listTagsOut);
					}
					else if (tagName == 'br') {
						instance._handleBreak(element, listTagsIn, listTagsOut);
					}
					else if (tagName == 'a') {
						instance._handleLink(element, listTagsIn, listTagsOut);
					}
					else if (tagName == 'strong' || tagName == 'b') {
						instance._handleStrong(element, listTagsIn, listTagsOut);
					}
					else if (tagName == 'em' || tagName == 'i') {
						instance._handleEm(element, listTagsIn, listTagsOut);
					}
					else if (tagName == 'img') {
						instance._handleImage(element, listTagsIn, listTagsOut);
					}
					else if (tagName == TAG_UNORDERED_LIST) {
						instance._handleUnorderedList(element, listTagsIn, listTagsOut);
					}
					else if (tagName == 'li') {
						instance._handleListItem(element, listTagsIn, listTagsOut);
					}
					else if (tagName == TAG_ORDERED_LIST) {
						instance._handleOrderedList(element, listTagsIn, listTagsOut);
					}
					else if (tagName == 'hr') {
						instance._handleHr(element, listTagsIn, listTagsOut);
					}
					else if (tagName == TAG_PRE) {
						instance._handlePre(element, listTagsIn, listTagsOut);
					}
					else if ((params = REGEX_HEADER.exec(tagName))) {
						instance._handleHeader(element, listTagsIn, listTagsOut, params);
					}
					else if (tagName == 'th') {
						instance._handleTableHeader(element, listTagsIn, listTagsOut);
					}
					else if (tagName == 'tr') {
						instance._handleTableRow(element, listTagsIn, listTagsOut);
					}
					else if (tagName == 'td') {
						instance._handleTableCell(element, listTagsIn, listTagsOut);
					}
				}
			},

			_handleElementEnd: function(element, listTagsIn, listTagsOut) {
				var instance = this;

				var tagName = element.tagName;

				if (tagName) {
					tagName = tagName.toLowerCase();
				}

				if (tagName === TAG_UNORDERED_LIST || tagName === TAG_ORDERED_LIST) {
					instance._ulLevel -= 1;

					if (!instance._isLastItemNewLine()) {
						instance._endResult.push(NEW_LINE);
					}
				}
				else if (tagName === 'table') {
					listTagsOut.push(NEW_LINE);
				}
			},

			_handleBreak: function(element, listTagsIn, listTagsOut) {
				listTagsIn.push('\\\\');
			},

			_handleEm: function(element, listTagsIn, listTagsOut) {
				listTagsIn.push(TAG_EMPHASIZE);
				listTagsOut.push(TAG_EMPHASIZE);
			},

			_handleHeader: function(element, listTagsIn, listTagsOut, params) {
				var instance = this;

				var res = new Array(parseInt(params[1], 10) + 1);
				res = res.join('=');

				if (!instance._isLastItemNewLine()) {
					listTagsIn.push(NEW_LINE);
				}

				listTagsIn.push(res, SPACE);
				listTagsOut.push(SPACE, res, NEW_LINE);
			},

			_handleHr: function(element, listTagsIn, listTagsOut) {
				var instance = this;

				if (!instance._isLastItemNewLine()) {
					listTagsIn.push(NEW_LINE);
				}

				listTagsIn.push('----', NEW_LINE);
			},

			_handleImage: function(element, listTagsIn, listTagsOut) {
				var attrAlt = element.alt;
				var attrSrc = element.src;

				listTagsIn.push('{{', attrSrc);

				if (attrAlt) {
					listTagsIn.push('|', attrAlt);
				}

				listTagsOut.push('}}');
			},

			_handleLink: function(element, listTagsIn, listTagsOut) {
				var hrefAttribute = element.href;

				listTagsIn.push('[[', hrefAttribute, '|');

				listTagsOut.push(']]');
			},

			_handleListItem: function(element, listTagsIn, listTagsOut) {
				var instance = this;

				var curListLevel = instance._ulLevel;
				var listItemTag = (tagName === TAG_UNORDERED_LIST) ?
					TAG_UNORDEREDLIST_ITEM : TAG_ORDEREDLIST_ITEM;
				var parentNode = element.parentNode;
				var tagName = parentNode.tagName.toLowerCase();

				var res = new Array(curListLevel + 1);
				res = res.join(listItemTag);

				if (!instance._isLastItemNewLine()){
					listTagsIn.push(NEW_LINE);
				}

				listTagsIn.push(res, SPACE);
			},

			_handleOrderedList: function(element, listTagsIn, listTagsOut) {
				var instance = this;

				instance._ulLevel += 1;
			},

			_handleParagraph: function(element, listTagsIn, listTagsOut) {
				var instance = this;

				var newLinesAtEnd = REGEX_LASTCHAR_NEWLINE.exec(instance._endResult.slice(-1));
				var count = newLinesAtEnd ? newLinesAtEnd[1].length : 0;

				while (count++ < 2) {
					listTagsIn.push(NEW_LINE);
				}

				listTagsOut.push(NEW_LINE, NEW_LINE);
			},

			_handlePre: function(element, listTagsIn, listTagsOut) {
				var instance = this;

				if (!instance._isLastItemNewLine()) {
					listTagsIn.push(NEW_LINE);
				}

				listTagsIn.push('{{{', NEW_LINE);
				listTagsOut.push(NEW_LINE, '}}}', NEW_LINE);
			},

			_handleStrong: function(element, listTagsIn, listTagsOut) {
				listTagsIn.push(TAG_BOLD);
				listTagsOut.push(TAG_BOLD);
			},

			_handleStyles: function(element, stylesTagsIn, stylesTagsOut) {
				var style = element.style;

				if (style) {
					var cssText = style.cssText;

					if (REGEX_BOLD.test(cssText)) {
						stylesTagsIn.push(TAG_BOLD);
						stylesTagsOut.push(TAG_BOLD);
					}

					if (REGEX_ITALIC.test(cssText)) {
						stylesTagsIn.push(TAG_EMPHASIZE);
						stylesTagsOut.push(TAG_EMPHASIZE);
					}
				}
			},

			_handleTableCell: function(element, listTagsIn, listTagsOut) {
				listTagsIn.push('|');
			},

			_handleTableHeader: function(element, listTagsIn, listTagsOut) {
				listTagsIn.push('|', '=');
			},

			_handleTableRow: function(element, listTagsIn, listTagsOut) {
				listTagsIn.push(NEW_LINE);
				listTagsOut.push('|');
			},

			_handleUnorderedList: function(element, listTagsIn, listTagsOut) {
				var instance = this;

				instance._ulLevel += 1;
			},

			_pushTagList: function(tagsList) {
				var instance = this;

				var endResult, i, length, tag;

				endResult = instance._endResult;
				length = tagsList.length;

				for (i = 0; i < length; i++) {
					tag = tagsList[i];

					endResult.push(tag);
				}
			}
		}
	}
);

A.HTML2CreoleConvertor = HTML2CreoleConvertor;
<commit_msg>AUI-291 - Code cleanups<commit_after>var Lang = A.Lang;

var NEW_LINE = '\n';

var TAG_BOLD = '**';
var TAG_EMPHASIZE = '//';
var TAG_PRE = 'pre';
var TAG_ORDERED_LIST = 'ol';
var TAG_ORDEREDLIST_ITEM = '#';
var TAG_UNORDERED_LIST = 'ul';
var TAG_UNORDEREDLIST_ITEM = '*';

var REGEX_BOLD = /(?:^|\s)font-weight\s*:\s*bold\s*;?/i;
var REGEX_HEADER = /^h([1-6])$/i;
var REGEX_ITALIC = /(?:^|\s)font-style\s*:\s*italic\s*;?/i;
var REGEX_NOT_WHITESPACE = /[^\t\n\r ]/;
var REGEX_LASTCHAR_NEWLINE = /(\r?\n\s*)$/;

var SPACE = ' ';

var HTML2CreoleConvertor = A.Component.create(
	{
		NAME: 'domparsercreole',

		ATTRS: {
			data: {
				value: null,
				validator: Lang.isString
			}
		},

		EXTENDS: A.Base,

		prototype: {
			_endResult: null,

			_ulLevel: 0,

			initializer: function() {

			},

			convert: function(data) {
				var instance = this;

				if (data) {
					this.set('data', data);
				} else {
					data = this.get('data');
				}

				var node = A.config.doc.createElement('div');
				node.innerHTML = data;

				instance._handle(node);

				var endResult = instance._endResult.join('');

				instance._endResult = null;

				return endResult;
			},

			_isAllWS: function(node) {
				return !(REGEX_NOT_WHITESPACE.test(node.data));
			},

			_isIgnorable: function(node) {
				var instance = this;

				var nodeType = node.nodeType;

				return (nodeType == 8) ||
					((nodeType == 3) && instance._isAllWS(node));
			},

			_isLastItemNewLine: function(node) {
				var instance = this;

				var endResult = instance._endResult;

				return (endResult && REGEX_LASTCHAR_NEWLINE.test(endResult.slice(-1)));
			},

			_handle: function(node) {
				var instance = this;

				var child, children, data, i, listTagsIn, listTagsOut,
					length, stylesTagsIn, stylesTagsOut, pushTagList;

				if (!Lang.isArray(instance._endResult)) {
					instance._endResult = [];
				}

				children = node.childNodes;
				pushTagList = instance._pushTagList;
				length = children.length;

				for (i = 0; i < length; i++) {
					listTagsIn = [];
					listTagsOut = [];

					stylesTagsIn = [];
					stylesTagsOut = [];

					child = children[i];

					if (instance._isIgnorable(child)) {
						continue;
					}

					instance._handleElementStart(child, listTagsIn, listTagsOut);
					instance._handleStyles(child, stylesTagsIn, stylesTagsOut);

					pushTagList.call(instance, listTagsIn);
					pushTagList.call(instance, stylesTagsIn);

					instance._handle(child);

					instance._handleElementEnd(child, listTagsIn, listTagsOut);

					pushTagList.call(instance, stylesTagsOut.reverse());
					pushTagList.call(instance, listTagsOut);
				}

				data = node.data;

				instance._handleData(data, node);
			},

			_handleData: function(data, element) {
				var instance = this;

				if (Lang.isValue(data)) {
					instance._endResult.push(data);
				}
			},

			_handleElementStart: function(element, listTagsIn, listTagsOut) {
				var instance = this;

				var tagName = element.tagName;
				var params;

				if (tagName) {
					tagName = tagName.toLowerCase();

					if (tagName == 'p') {
						instance._handleParagraph(element, listTagsIn, listTagsOut);
					}
					else if (tagName == 'br') {
						instance._handleBreak(element, listTagsIn, listTagsOut);
					}
					else if (tagName == 'a') {
						instance._handleLink(element, listTagsIn, listTagsOut);
					}
					else if (tagName == 'strong' || tagName == 'b') {
						instance._handleStrong(element, listTagsIn, listTagsOut);
					}
					else if (tagName == 'em' || tagName == 'i') {
						instance._handleEm(element, listTagsIn, listTagsOut);
					}
					else if (tagName == 'img') {
						instance._handleImage(element, listTagsIn, listTagsOut);
					}
					else if (tagName == TAG_UNORDERED_LIST) {
						instance._handleUnorderedList(element, listTagsIn, listTagsOut);
					}
					else if (tagName == 'li') {
						instance._handleListItem(element, listTagsIn, listTagsOut);
					}
					else if (tagName == TAG_ORDERED_LIST) {
						instance._handleOrderedList(element, listTagsIn, listTagsOut);
					}
					else if (tagName == 'hr') {
						instance._handleHr(element, listTagsIn, listTagsOut);
					}
					else if (tagName == TAG_PRE) {
						instance._handlePre(element, listTagsIn, listTagsOut);
					}
					else if ((params = REGEX_HEADER.exec(tagName))) {
						instance._handleHeader(element, listTagsIn, listTagsOut, params);
					}
					else if (tagName == 'th') {
						instance._handleTableHeader(element, listTagsIn, listTagsOut);
					}
					else if (tagName == 'tr') {
						instance._handleTableRow(element, listTagsIn, listTagsOut);
					}
					else if (tagName == 'td') {
						instance._handleTableCell(element, listTagsIn, listTagsOut);
					}
				}
			},

			_handleElementEnd: function(element, listTagsIn, listTagsOut) {
				var instance = this;

				var tagName = element.tagName;

				if (tagName) {
					tagName = tagName.toLowerCase();
				}

				if (tagName === TAG_UNORDERED_LIST || tagName === TAG_ORDERED_LIST) {
					instance._ulLevel -= 1;

					if (!instance._isLastItemNewLine()) {
						instance._endResult.push(NEW_LINE);
					}
				}
				else if (tagName === 'table') {
					listTagsOut.push(NEW_LINE);
				}
			},

			_handleBreak: function(element, listTagsIn, listTagsOut) {
				listTagsIn.push('\\\\');
			},

			_handleEm: function(element, listTagsIn, listTagsOut) {
				listTagsIn.push(TAG_EMPHASIZE);
				listTagsOut.push(TAG_EMPHASIZE);
			},

			_handleHeader: function(element, listTagsIn, listTagsOut, params) {
				var instance = this;

				var res = new Array(parseInt(params[1], 10) + 1);
				res = res.join('=');

				if (!instance._isLastItemNewLine()) {
					listTagsIn.push(NEW_LINE);
				}

				listTagsIn.push(res, SPACE);
				listTagsOut.push(SPACE, res, NEW_LINE);
			},

			_handleHr: function(element, listTagsIn, listTagsOut) {
				var instance = this;

				if (!instance._isLastItemNewLine()) {
					listTagsIn.push(NEW_LINE);
				}

				listTagsIn.push('----', NEW_LINE);
			},

			_handleImage: function(element, listTagsIn, listTagsOut) {
				var attrAlt = element.alt;
				var attrSrc = element.src;

				listTagsIn.push('{{', attrSrc);

				if (attrAlt) {
					listTagsIn.push('|', attrAlt);
				}

				listTagsOut.push('}}');
			},

			_handleLink: function(element, listTagsIn, listTagsOut) {
				var hrefAttribute = element.href;

				listTagsIn.push('[[', hrefAttribute, '|');

				listTagsOut.push(']]');
			},

			_handleListItem: function(element, listTagsIn, listTagsOut) {
				var instance = this;

				var curListLevel = instance._ulLevel;
				var listItemTag = (tagName === TAG_UNORDERED_LIST) ?
					TAG_UNORDEREDLIST_ITEM : TAG_ORDEREDLIST_ITEM;
				var parentNode = element.parentNode;
				var tagName = parentNode.tagName.toLowerCase();

				var res = new Array(curListLevel + 1);
				res = res.join(listItemTag);

				if (!instance._isLastItemNewLine()){
					listTagsIn.push(NEW_LINE);
				}

				listTagsIn.push(res, SPACE);
			},

			_handleOrderedList: function(element, listTagsIn, listTagsOut) {
				var instance = this;

				instance._ulLevel += 1;
			},

			_handleParagraph: function(element, listTagsIn, listTagsOut) {
				var instance = this;

				var newLinesAtEnd = REGEX_LASTCHAR_NEWLINE.exec(instance._endResult.slice(-1));
				var count = newLinesAtEnd ? newLinesAtEnd[1].length : 0;

				while (count++ < 2) {
					listTagsIn.push(NEW_LINE);
				}

				listTagsOut.push(NEW_LINE, NEW_LINE);
			},

			_handlePre: function(element, listTagsIn, listTagsOut) {
				var instance = this;

				if (!instance._isLastItemNewLine()) {
					listTagsIn.push(NEW_LINE);
				}

				listTagsIn.push('{{{', NEW_LINE);
				listTagsOut.push(NEW_LINE, '}}}', NEW_LINE);
			},

			_handleStrong: function(element, listTagsIn, listTagsOut) {
				listTagsIn.push(TAG_BOLD);
				listTagsOut.push(TAG_BOLD);
			},

			_handleStyles: function(element, stylesTagsIn, stylesTagsOut) {
				var style = element.style;

				if (style) {
					var cssText = style.cssText;

					if (REGEX_BOLD.test(cssText)) {
						stylesTagsIn.push(TAG_BOLD);
						stylesTagsOut.push(TAG_BOLD);
					}

					if (REGEX_ITALIC.test(cssText)) {
						stylesTagsIn.push(TAG_EMPHASIZE);
						stylesTagsOut.push(TAG_EMPHASIZE);
					}
				}
			},

			_handleTableCell: function(element, listTagsIn, listTagsOut) {
				listTagsIn.push('|');
			},

			_handleTableHeader: function(element, listTagsIn, listTagsOut) {
				listTagsIn.push('|', '=');
			},

			_handleTableRow: function(element, listTagsIn, listTagsOut) {
				listTagsIn.push(NEW_LINE);
				listTagsOut.push('|');
			},

			_handleUnorderedList: function(element, listTagsIn, listTagsOut) {
				var instance = this;

				instance._ulLevel += 1;
			},

			_pushTagList: function(tagsList) {
				var instance = this;

				var endResult, i, length, tag;

				endResult = instance._endResult;
				length = tagsList.length;

				for (i = 0; i < length; i++) {
					tag = tagsList[i];

					endResult.push(tag);
				}
			}
		}
	}
);

A.HTML2CreoleConvertor = HTML2CreoleConvertor;
<|endoftext|>


<commit_before>angular.module("Prometheus.filters").filter('toPercent', function() {
  return function(input) {
    return parseFloat(input, 10) * 100 + "%";
  }
});

angular.module("Prometheus.filters").filter('toPercentile', function() {
  return function(input) {
    return parseFloat(input, 10) * 100 + "th";
  }
});

angular.module("Prometheus.filters").filter('hostname', function() {
  return function(input) {
    var a = document.createElement("a");
    a.href = input;
    return a.host;
  }
});

angular.module("Prometheus.filters").filter('regex', function() {
  return function(input, regex, replace) {
    return input.replace(new RegExp(regex, "g"), replace);
  }
});
<commit_msg>Add hostname and hostnamef filters<commit_after>angular.module("Prometheus.filters").filter('toPercent', function() {
  return function(input) {
    return parseFloat(input, 10) * 100 + "%";
  }
});

angular.module("Prometheus.filters").filter('toPercentile', function() {
  return function(input) {
    return parseFloat(input, 10) * 100 + "th";
  }
});

angular.module("Prometheus.filters").filter('hostnameFqdn', function() {
  return function(input) {
    var a = document.createElement("a");
    a.href = input;
    return a.host;
  }
});

angular.module("Prometheus.filters").filter('hostname', function() {
  return function(input) {
    var a = document.createElement("a");
    a.href = input;
    return a.host.split(".", 1)[0];
  }
});

angular.module("Prometheus.filters").filter('regex', function() {
  return function(input, regex, replace) {
    return input.replace(new RegExp(regex, "g"), replace);
  }
});
<|endoftext|>


<commit_before>var Lang = A.Lang,

	BOUNDING_BOX = 'boundingBox',
	CONTENT_BOX = 'contentBox',
	HIDE = 'hide',
	HOST = 'host',
	MESSAGE_EL = 'messageEl',
	NAME = 'loadingmask',
	POSITION = 'position',
	SHOW = 'show',
	STATIC = 'static',
	STRINGS = 'strings',
	TARGET = 'target',
	TOGGLE = 'toggle',

	getClassName = A.ClassNameManager.getClassName,

	CSS_LOADINGMASK = getClassName(NAME),
	CSS_MASKED = getClassName(NAME, 'masked'),
	CSS_MASKED_RELATIVE = getClassName(NAME, 'masked', 'relative'),
	CSS_MESSAGE_LOADING = getClassName(NAME, 'message'),
	CSS_MESSAGE_LOADING_CONTENT = getClassName(NAME, 'message', 'content'),

	TPL_MESSAGE_LOADING = '

{0}

';

var LoadingMask = function(config) {
	LoadingMask.superclass.constructor.apply(this, arguments);
};

LoadingMask.NAME = NAME;
LoadingMask.NS = NAME;

LoadingMask.ATTRS = {
	messageEl: {
		valueFn: function(val) {
			var instance = this;
			var strings = instance.get(STRINGS);

			return A.Node.create(
				A.substitute(TPL_MESSAGE_LOADING, [strings.loading])
			);
		}
	},

	strings: {
		value: {
			loading: 'Loading…'
		}
	},

	target: {
		setter: function() {
			var instance = this;
			var target = instance.get(HOST);

			if (target instanceof A.Widget) {
				target = target.get(CONTENT_BOX);
			}

			return target;
		},
		value: null
	}
};

A.extend(
	LoadingMask,
	A.Plugin.Base,
	{
		/*
		* Lifecycle
		*/
		initializer: function(config) {
			var instance = this;

			instance.IGNORED_ATTRS = A.merge(
				{
					host: true
				},
				LoadingMask.ATTRS
			);

			instance.renderUI();
			instance.bindUI();

			instance._createDynamicAttrs(config);
		},

		renderUI: function() {
			var instance = this;
			var strings = instance.get(STRINGS);

			instance._renderOverlayMask();

			instance.overlayMask.get(BOUNDING_BOX).append(
				instance.get(MESSAGE_EL)
			);
		},

		bindUI: function() {
			var instance = this;

			instance._bindOverlayMaskUI();
		},

		_bindOverlayMaskUI: function() {
			var instance = this;

			instance.overlayMask.after('visibleChange', instance._afterVisibleChange, instance);
		},

		/*
		* Methods
		*/
		centerMessage: function() {
			var instance = this;

			instance.get(MESSAGE_EL).center(
				instance.overlayMask.get(BOUNDING_BOX)
			);
		},

		refreshMask: function() {
			var instance = this;

			instance.overlayMask.refreshMask();

			instance.centerMessage();
		},

		_afterVisibleChange: function(event) {
			var instance = this;
			var target = instance.get(TARGET);
			var isStaticPositioned = (target.getStyle(POSITION) == STATIC);

			target.toggleClass(CSS_MASKED, (event.newVal));
			target.toggleClass(CSS_MASKED_RELATIVE, (event.newVal && isStaticPositioned));

			if (event.newVal) {
				instance.refreshMask();
			}
		},

		_renderOverlayMask: function() {
			var instance = this;
			var target = instance.get(TARGET);

			instance.overlayMask = new A.OverlayMask(
				{
					target: target,
					cssClass: CSS_LOADINGMASK
				}
			).render(target);
		},

		_createDynamicAttrs: function(config) {
			var instance = this;

			A.each(config, function(value, key) {
				var ignoredAttr = instance.IGNORED_ATTRS[key];

				if (!ignoredAttr) {
					instance.addAttr(key, {
						setter: function(val) {
							this.overlayMask.set(key, val);

							return val;
						},
						value: value
					});
				}
			});
		}
	}
);

A.each([HIDE, SHOW, TOGGLE], function(method) {
	LoadingMask.prototype[method] = function() {
		this.overlayMask[method]();
	};
});

A.LoadingMask = LoadingMask;<commit_msg>Documentation - LoadingMask<commit_after>/**
 * The LoadingMask Utility
 *
 * @module aui-loading-mask
 */

var Lang = A.Lang,

	BOUNDING_BOX = 'boundingBox',
	CONTENT_BOX = 'contentBox',
	HIDE = 'hide',
	HOST = 'host',
	MESSAGE_EL = 'messageEl',
	NAME = 'loadingmask',
	POSITION = 'position',
	SHOW = 'show',
	STATIC = 'static',
	STRINGS = 'strings',
	TARGET = 'target',
	TOGGLE = 'toggle',

	getClassName = A.ClassNameManager.getClassName,

	CSS_LOADINGMASK = getClassName(NAME),
	CSS_MASKED = getClassName(NAME, 'masked'),
	CSS_MASKED_RELATIVE = getClassName(NAME, 'masked', 'relative'),
	CSS_MESSAGE_LOADING = getClassName(NAME, 'message'),
	CSS_MESSAGE_LOADING_CONTENT = getClassName(NAME, 'message', 'content'),

	TPL_MESSAGE_LOADING = '

{0}

';

/**
 *

 *
 * A base class for LoadingMask, providing:
 *

 *
Cross browser mask functionality to cover an element or the entire page

 *
Customizable mask (i.e., background, opacity)

 *
Display a centered "loading" message on the masked node

 *

 *
 * Quick Example:

 *
 *
node.plug(A.LoadingMask, { background: '#000' });

 *
 * Check the list of Configuration Attributes available for
 * LoadingMask.
 *
 * @param config {Object} Object literal specifying widget configuration properties.
 *
 * @class LoadingMask
 * @constructor
 * @extends Plugin.Base
 */
var LoadingMask = function(config) {
	LoadingMask.superclass.constructor.apply(this, arguments);
};

/**
 * Static property provides a string to identify the class.
 *
 * @property LoadingMask.NAME
 * @type String
 * @static
 */
LoadingMask.NAME = NAME;

/**
 * Static property provides a string to identify the namespace.
 *
 * @property LoadingMask.NAME
 * @type String
 * @static
 */
LoadingMask.NS = NAME;

/**
 * Static property used to define the default attribute
 * configuration for the LoadingMask.
 *
 * @property LoadingMask.ATTRS
 * @type Object
 * @static
 */
LoadingMask.ATTRS = {
	/**
	 * Node element to display the message.
	 *
	 * @attribute messageEl
	 * @default Generated HTML div element.
	 * @type String
	 */
	messageEl: {
		valueFn: function(val) {
			var instance = this;
			var strings = instance.get(STRINGS);

			return A.Node.create(
				A.substitute(TPL_MESSAGE_LOADING, [strings.loading])
			);
		}
	},

	/**
	 * Strings used on the LoadingMask. See
     * strings.
	 *
	 * @attribute strings
	 * @default { loading: 'Loading…' }
	 * @type Object
	 */
	strings: {
		value: {
			loading: 'Loading…'
		}
	},

	/**
	 * Node where the mask will be positioned and re-dimensioned.
	 *
	 * @attribute target
	 * @default null
	 * @type Node | Widget
	 */
	target: {
		setter: function() {
			var instance = this;
			var target = instance.get(HOST);

			if (target instanceof A.Widget) {
				target = target.get(CONTENT_BOX);
			}

			return target;
		},
		value: null
	}
};

A.extend(
	LoadingMask,
	A.Plugin.Base,
	{
		/**
		 * Construction logic executed during LoadingMask instantiation. Lifecycle.
		 *
		 * @method initializer
		 * @protected
		 */
		initializer: function(config) {
			var instance = this;

			instance.IGNORED_ATTRS = A.merge(
				{
					host: true
				},
				LoadingMask.ATTRS
			);

			instance.renderUI();
			instance.bindUI();

			instance._createDynamicAttrs(config);
		},

		/**
		 * Create the DOM structure for the LoadingMask. Lifecycle.
		 *
		 * @method renderUI
		 * @protected
		 */
		renderUI: function() {
			var instance = this;
			var strings = instance.get(STRINGS);

			instance._renderOverlayMask();

			instance.overlayMask.get(BOUNDING_BOX).append(
				instance.get(MESSAGE_EL)
			);
		},

		/**
		 * Bind the events on the LoadingMask UI. Lifecycle.
		 *
		 * @method bindUI
		 * @protected
		 */
		bindUI: function() {
			var instance = this;

			instance._bindOverlayMaskUI();
		},

		/**
		 * Bind events to the
         * overlayMask.
		 *
		 * @method _bindOverlayMaskUI
		 * @protected
		 */
		_bindOverlayMaskUI: function() {
			var instance = this;

			instance.overlayMask.after('visibleChange', instance._afterVisibleChange, instance);
		},

		/**
		 * Center the
         * messageEl with the
         * target node.
		 *
		 * @method centerMessage
		 */
		centerMessage: function() {
			var instance = this;

			instance.get(MESSAGE_EL).center(
				instance.overlayMask.get(BOUNDING_BOX)
			);
		},

		/**
		 * Invoke the
         * overlayMask
         * refreshMask method.
		 *
		 * @method refreshMask
		 */
		refreshMask: function() {
			var instance = this;

			instance.overlayMask.refreshMask();

			instance.centerMessage();
		},

		/**
		 * Fires after the value of the
		 * visible attribute change.
		 *
		 * @method _afterVisibleChange
		 * @param {EventFacade} event
		 * @protected
		 */
		_afterVisibleChange: function(event) {
			var instance = this;
			var target = instance.get(TARGET);
			var isStaticPositioned = (target.getStyle(POSITION) == STATIC);

			target.toggleClass(CSS_MASKED, (event.newVal));
			target.toggleClass(CSS_MASKED_RELATIVE, (event.newVal && isStaticPositioned));

			if (event.newVal) {
				instance.refreshMask();
			}
		},

		/**
		 * Render
         * overlayMask
         * instance.
		 *
		 * @method _renderOverlayMask
		 * @protected
		 */
		_renderOverlayMask: function() {
			var instance = this;
			var target = instance.get(TARGET);

			/**
			 * Stores the OverlayMask used
             * internally.
			 *
			 * @property overlayMask
			 * @type OverlayMask
			 * @protected
			 */
			instance.overlayMask = new A.OverlayMask(
				{
					target: target,
					cssClass: CSS_LOADINGMASK
				}
			).render(target);
		},

		/**
		 * Create dynamic attributes listeners to invoke the setter on
         * overlayMask after
         * the attribute is set on the LoadingMask instance.
		 *
		 * @method _createDynamicAttrs
		 * @param {Object} config Object literal specifying widget configuration properties.
		 * @protected
		 */
		_createDynamicAttrs: function(config) {
			var instance = this;

			A.each(config, function(value, key) {
				var ignoredAttr = instance.IGNORED_ATTRS[key];

				if (!ignoredAttr) {
					instance.addAttr(key, {
						setter: function(val) {
							this.overlayMask.set(key, val);

							return val;
						},
						value: value
					});
				}
			});
		}
	}
);

A.each([HIDE, SHOW, TOGGLE], function(method) {
	/**
	 * Invoke the
     * overlayMask
     * hide method.
	 *
	 * @method hide
	 */

	/**
	 * Invoke the
     * overlayMask
     * show method.
	 *
	 * @method show
	 */

	/**
	 * Invoke the
     * overlayMask
     * toggle method.
	 *
	 * @method toggle
	 */
	LoadingMask.prototype[method] = function() {
		this.overlayMask[method]();
	};
});

A.LoadingMask = LoadingMask;<|endoftext|>


<commit_before>Travis.Controllers.Sidebar = SC.Object.extend({
  cookie: 'sidebar_minimized',

  init: function() {
    Travis.Controllers.Workers.create();
    Travis.Controllers.Jobs.create({ queue: 'builds.common'  });
    Travis.Controllers.Jobs.create({ queue: 'builds.rails' });
    Travis.Controllers.Jobs.create({ queue: 'builds.erlang' });
    Travis.Controllers.Jobs.create({ queue: 'builds.php' });
    Travis.Controllers.Jobs.create({ queue: 'builds.node' });

    $(".slider").click(function() { this.toggle(); }.bind(this));
    if($.cookie(this.cookie) === 'true') { this.minimize(); }
    this.persist();
  },

  toggle: function() {
    this.isMinimized() ? this.maximize() : this.minimize();
    this.persist();
  },

  isMinimized: function() {
    return $('#right').hasClass('minimized');
  },

  minimize: function() {
    $('#right').addClass('minimized');
    $('#main').addClass('maximized');
  },

  maximize: function() {
    $('#right').removeClass('minimized');
    $('#main').removeClass('maximized');
  },

  persist: function() {
    $.cookie(this.cookie, this.isMinimized());
  }
});
<commit_msg>queue name will be node_js<commit_after>Travis.Controllers.Sidebar = SC.Object.extend({
  cookie: 'sidebar_minimized',

  init: function() {
    Travis.Controllers.Workers.create();
    Travis.Controllers.Jobs.create({ queue: 'builds.common'  });
    Travis.Controllers.Jobs.create({ queue: 'builds.rails' });
    Travis.Controllers.Jobs.create({ queue: 'builds.erlang' });
    Travis.Controllers.Jobs.create({ queue: 'builds.php' });
    Travis.Controllers.Jobs.create({ queue: 'builds.node_js' });

    $(".slider").click(function() { this.toggle(); }.bind(this));
    if($.cookie(this.cookie) === 'true') { this.minimize(); }
    this.persist();
  },

  toggle: function() {
    this.isMinimized() ? this.maximize() : this.minimize();
    this.persist();
  },

  isMinimized: function() {
    return $('#right').hasClass('minimized');
  },

  minimize: function() {
    $('#right').addClass('minimized');
    $('#main').addClass('maximized');
  },

  maximize: function() {
    $('#right').removeClass('minimized');
    $('#main').removeClass('maximized');
  },

  persist: function() {
    $.cookie(this.cookie, this.isMinimized());
  }
});
<|endoftext|>


<commit_before>CATARSE.ProjectsShowView = Backbone.View.extend({

  initialize: function() {
    _.bindAll(this, "render", "BackerView", "BackersView", "about", "updates", "backers", "comments", "embed", "isValid", "backWithReward")
    CATARSE.router.route("", "index", this.about)
    CATARSE.router.route("about", "about", this.about)
    CATARSE.router.route("updates", "updates", this.updates)
    CATARSE.router.route(/updates\/\d+/, "updates", this.updates)
    CATARSE.router.route("backers", "backers", this.backers)
    CATARSE.router.route("comments", "comments", this.comments)
    CATARSE.router.route("embed", "embed", this.embed)

    this.$('a.destroy_update').live('ajax:beforeSend', function(event, data){
      $(event.target).next('.deleting_update').show();
    });

    var that = this;
    this.$('a.destroy_update').live('ajax:success', function(event, data){
      var target = $('.updates_wrapper');
      target.html(data);
      that.$('a#updates_link .count').html(' (' + that.$('.updates_wrapper ul.collection_list > li').length + ')');
      $(event.target).next('.deleting_update').hide();
    });

    this.project = new CATARSE.Project($('#project_description').data("project"))
    this.render()
  },

  events: {
    "click #show_formatting_tips": "showFormattingTips",
    "keyup form input[type=text],textarea": "validate",
    "click #project_link": "selectTarget",
    "click #project_embed textarea": "selectTarget",
    "click #rewards .clickable": "backWithReward"
    //"click #pledge input[type=submit]": "requireLogin"
  },

  UpdatesForm: Backbone.View.extend({
    el: 'form#new_update',
    events: {
      "click #update_submit" : "submit",
      "keyup #project_updates #update_comment" : "validate_comment"
    },

    initialize: function() {
      _.bindAll(this);
      this.loading = this.$('.loading_updates');
    },

    submit: function(){
      this.validate_comment()
      var that = this;
      var form = $(this.el);
      that.loading.show();
      $.post(form.prop('action'), form.serialize(), null, 'html')
        .success(function(data){
          var target = $('.updates_wrapper');
          target.html(data);
          $('a#updates_link .count').html(' (' + $('.updates_wrapper ul.collection_list > li').length + ')');
          that.loading.hide();
          that.el.reset();
        });
      return false;
    },
    validate_comment: function(el){
      var target = $("#project_updates #update_comment");
      if(target.val() == ''){
        target.addClass('error');
        target.removeClass('ok');
      }else{
        target.removeClass('error');
        target.addClass('ok');
      }
    }
  }),

  BackerView: CATARSE.ModelView.extend({
    template: function(vars){
      return $('#backer_template').html()
    }
  }),

  BackersView: CATARSE.PaginatedView.extend({
		template: function(vars){
      return $('#backers_template').html()
    },
    emptyTemplate: function(){
      return $('#empty_backers_template').html()
    }
  }),

  about: function() {
    this.selectItem("about")
  },

  updates: function() {
    this.selectItem("updates")
    this.updatesForm = new this.UpdatesForm();
    this.$("#project_updates [type=submit]").removeProp('disabled')
  },

  comments: function() {
    this.selectItem("comments")
  },

  backers: function() {
    this.selectItem("backers")
    this.backersView = new this.BackersView({
      modelView: this.BackerView,
      collection: new CATARSE.Backers({url: '/' + CATARSE.locale + '/projects/' + this.project.id + '/backers'}),
      loading: this.$("#loading"),
      el: this.$("#project_backers")
    })
  },

  embed: function(){
    this.$('#embed_overlay').show()
    this.$('#project_embed').fadeIn()
  },

  selectItem: function(item) {
    this.$('#project_embed').hide()
    this.$('#embed_overlay').hide()
    this.$('#loading img').hide()
    this.$("#project_content .content").hide()
    this.$("#project_content #project_" + item + ".content").show()
    var link = this.$("#project_menu #" + item + "_link")
    this.$('#project_menu a').removeClass('selected')
    link.addClass('selected')
  },

  showFormattingTips: function(event){
    event.preventDefault()
    this.$('#show_formatting_tips').hide()
    this.$('#formatting_tips').slideDown()
  },

  isValid: function(form){
    var valid = true
    form.find('input[type=text],textarea').each(function(){
      if($(this).parent().hasClass('required') && $.trim($(this).val()) == "") {
        valid = false
      }
    })
    return valid
  },

  validate: function(event){
    var form = $(event.target).parentsUntil('form')
    var submit = form.find('[type=submit]')
    if(this.isValid(form))
      submit.attr('disabled', false)
    else
      submit.attr('disabled', true)
  },

  selectTarget: function(event){
    event.preventDefault()
    $(event.target).select()
  },

  backWithReward: function(event){
    var element = $(event.target)
    if(element.is('a') || element.is('textarea') || element.is('button'))
      return true
    if(!element.is('li'))
      element = element.parentsUntil('li')
    var url = element.find('input[type=hidden]').val()
    window.location.href = url;
    //CATARSE.requireLogin(event, url)
  },

  requireLogin: function(event) {
    CATARSE.requireLogin(event)
  }

})
<commit_msg>fixing facebook like button in about/updates in projects<commit_after>CATARSE.ProjectsShowView = Backbone.View.extend({

  initialize: function() {
    _.bindAll(this, "render", "BackerView", "BackersView", "about", "updates", "backers", "comments", "embed", "isValid", "backWithReward")
    CATARSE.router.route("", "index", this.about)
    CATARSE.router.route("about", "about", this.about)
    CATARSE.router.route("updates", "updates", this.updates)
    CATARSE.router.route(/updates\/\d+/, "updates", this.updates)
    CATARSE.router.route("backers", "backers", this.backers)
    CATARSE.router.route("comments", "comments", this.comments)
    CATARSE.router.route("embed", "embed", this.embed)

    this.$('a.destroy_update').live('ajax:beforeSend', function(event, data){
      $(event.target).next('.deleting_update').show();
    });

    var that = this;
    this.$('a.destroy_update').live('ajax:success', function(event, data){
      var target = $('.updates_wrapper');
      target.html(data);
      that.$('a#updates_link .count').html(' (' + that.$('.updates_wrapper ul.collection_list > li').length + ')');
      $(event.target).next('.deleting_update').hide();
    });

    this.project = new CATARSE.Project($('#project_description').data("project"))
    this.render()
  },

  events: {
    "click #show_formatting_tips": "showFormattingTips",
    "keyup form input[type=text],textarea": "validate",
    "click #project_link": "selectTarget",
    "click #project_embed textarea": "selectTarget",
    "click #rewards .clickable": "backWithReward"
    //"click #pledge input[type=submit]": "requireLogin"
  },

  UpdatesForm: Backbone.View.extend({
    el: 'form#new_update',
    events: {
      "click #update_submit" : "submit",
      "keyup #project_updates #update_comment" : "validate_comment"
    },

    initialize: function() {
      _.bindAll(this);
      this.loading = this.$('.loading_updates');
    },

    submit: function(){
      this.validate_comment()
      var that = this;
      var form = $(this.el);
      that.loading.show();
      $.post(form.prop('action'), form.serialize(), null, 'html')
        .success(function(data){
          var target = $('.updates_wrapper');
          target.html(data);
          $('a#updates_link .count').html(' (' + $('.updates_wrapper ul.collection_list > li').length + ')');
          that.loading.hide();
          that.el.reset();
        });
      return false;
    },
    validate_comment: function(el){
      var target = $("#project_updates #update_comment");
      if(target.val() == ''){
        target.addClass('error');
        target.removeClass('ok');
      }else{
        target.removeClass('error');
        target.addClass('ok');
      }
    }
  }),

  BackerView: CATARSE.ModelView.extend({
    template: function(vars){
      return $('#backer_template').html()
    }
  }),

  BackersView: CATARSE.PaginatedView.extend({
		template: function(vars){
      return $('#backers_template').html()
    },
    emptyTemplate: function(){
      return $('#empty_backers_template').html()
    }
  }),

  about: function() {
    this.selectItem("about")
  },

  updates: function() {
    this.selectItem("updates")
    this.updatesForm = new this.UpdatesForm();
    this.$("#project_updates [type=submit]").removeProp('disabled')
  },

  comments: function() {
    this.selectItem("comments")
  },

  backers: function() {
    this.selectItem("backers")
    this.backersView = new this.BackersView({
      modelView: this.BackerView,
      collection: new CATARSE.Backers({url: '/' + CATARSE.locale + '/projects/' + this.project.id + '/backers'}),
      loading: this.$("#loading"),
      el: this.$("#project_backers")
    })
  },

  embed: function(){
    this.$('#embed_overlay').show()
    this.$('#project_embed').fadeIn()
  },

  selectItem: function(item) {
    this.$('#project_embed').hide()
    this.$('#embed_overlay').hide()
    this.$('#loading img').hide()
    this.$("#project_content .content").hide()
    this.$("#project_content #project_" + item + ".content").show()
    var link = this.$("#project_menu #" + item + "_link")
    this.$('#project_menu a').removeClass('selected')
    link.addClass('selected')
    FB.XFBML.parse();
  },

  showFormattingTips: function(event){
    event.preventDefault()
    this.$('#show_formatting_tips').hide()
    this.$('#formatting_tips').slideDown()
  },

  isValid: function(form){
    var valid = true
    form.find('input[type=text],textarea').each(function(){
      if($(this).parent().hasClass('required') && $.trim($(this).val()) == "") {
        valid = false
      }
    })
    return valid
  },

  validate: function(event){
    var form = $(event.target).parentsUntil('form')
    var submit = form.find('[type=submit]')
    if(this.isValid(form))
      submit.attr('disabled', false)
    else
      submit.attr('disabled', true)
  },

  selectTarget: function(event){
    event.preventDefault()
    $(event.target).select()
  },

  backWithReward: function(event){
    var element = $(event.target)
    if(element.is('a') || element.is('textarea') || element.is('button'))
      return true
    if(!element.is('li'))
      element = element.parentsUntil('li')
    var url = element.find('input[type=hidden]').val()
    window.location.href = url;
    //CATARSE.requireLogin(event, url)
  },

  requireLogin: function(event) {
    CATARSE.requireLogin(event)
  }

})
<|endoftext|>


<commit_before>APP.controllers.discussions = (function() {

  function init() {
    APP.controllers.groups.init();
    initControls();
    if ($('.follow').exists()) { initFollowing(); }
  }

  function initControls() {
    $(".discussion-page").on('click', '.edit-post-link', function() {
      $(this).parents(".user-post").addClass("editing");
      $(".edit-post-form textarea").autogrow({ onInitialize: true });
    }).on('click', '.cancel-edit-link', function() {
      $(this).parents(".user-post").removeClass("editing");
    });

    $('.show-all-comments-link').on("click", function() {
      $(this).parents(".post-comments").find(".comment-container").show();
      $(this).hide();
    });

    // Get Target for Mandrill Linking
    var target = getUrlVars()["target"];
    if (typeof target !== 'undefined') {
      $('html, body').animate({
        scrollTop: $(`#${target}`).offset().top
      }, 500);
    }

  }

  function initFollowing() {
    $('.follow').on('click', function(){
      $('.follow').toggleClass('-hide');
      //console.log($(this).attr("data-topic"));
    })
  }

  function getUrlVars() {
    var vars = {};
    var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
        vars[key] = value;
    });
    return vars;
  }

  return {
    init: init
  };

})();
<commit_msg>syntax bugfix<commit_after>APP.controllers.discussions = (function() {

  function init() {
    APP.controllers.groups.init();
    initControls();
    if ($('.follow').exists()) { initFollowing(); }
  }

  function initControls() {
    $(".discussion-page").on('click', '.edit-post-link', function() {
      $(this).parents(".user-post").addClass("editing");
      $(".edit-post-form textarea").autogrow({ onInitialize: true });
    }).on('click', '.cancel-edit-link', function() {
      $(this).parents(".user-post").removeClass("editing");
    });

    $('.show-all-comments-link').on("click", function() {
      $(this).parents(".post-comments").find(".comment-container").show();
      $(this).hide();
    });

    // Get Target for Mandrill Linking
    var target = getUrlVars()["target"];
    if (typeof target !== 'undefined') {
      $('html, body').animate({
        scrollTop: $('#'+target).offset().top
      }, 500);
    }

  }

  function initFollowing() {
    $('.follow').on('click', function(){
      $('.follow').toggleClass('-hide');
      //console.log($(this).attr("data-topic"));
    })
  }

  function getUrlVars() {
    var vars = {};
    var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
        vars[key] = value;
    });
    return vars;
  }

  return {
    init: init
  };

})();
<|endoftext|>


<commit_before>// Native
const {createServer} = require('http');

// External
const chokidar = require('chokidar');
const finalhandler = require('finalhandler');
const merge = require('merge');
const serveStatic = require('serve-static');

// Ours
const {pack, throws} = require('../../../utils/async');
const {log} = require('../../../utils');
const {exec} = require('../../../processes');
const {
  BUILD_DIR, D_KEY, DEFAULTS, KEY, TASK_NAMES
} = require('../build-basic-story/constants');
const build = require('../build-basic-story');
const {command} = require('../');
const {OPTIONS, USAGE, MESSAGES, HOSTNAME} = require('./constants');

module.exports = command({
  name: 'serve-basic-story',
  options: OPTIONS,
  usage: USAGE,
  configRequired: true
}, async function (argv, config) {
  const serveConfig = typeof config.serve === 'object' ? config.serve : {};
  const buildConfigKey = argv.debug ? D_KEY : KEY;

  const buildConfig = merge.recursive(true, DEFAULTS[buildConfigKey],
    typeof config[buildConfigKey] === 'object' ? config[buildConfigKey] : {}
  );

  throws(await build(argv.$));

  const serve = serveStatic(`${config.root}/${BUILD_DIR}`, {
    index: ['index.html']
  });

  const server = createServer((req, res) => {
    serve(req, res, finalhandler(req, res));
  });
  const [, domain] = await exec(`awk '/^domain/ {print $2}' /etc/resolv.conf`);
  const hostname = `${HOSTNAME}${domain ? `.${domain.replace('\n', '')}` : ''}`;
  const port = serveConfig.port || 8000;

  server.listen(port);

  log(MESSAGES.server(hostname, port));

  const changesQueue = [];

  async function flushChangesQueue() {
    if (changesQueue.length === 0) {
      return;
    }

    while (changesQueue.length > 0) {
      const {taskName, evt, path} = changesQueue.shift();

      log(MESSAGES.watchEvent(taskName, evt, path.replace(config.root, '')));
      throws(await build(argv.$.concat(['--taskName', taskName])));
    }

    log(MESSAGES.STILL_WATCHING);
  }

  const watchAndServe = pack(new Promise((resolve, reject) => {
    const watchedTaskNames = TASK_NAMES.reduce((watchedTaskNames, taskName) => {
      const taskConfig = buildConfig[taskName];

      if (
        typeof taskConfig !== 'object' ||
        taskConfig.from == null ||
        (
          taskConfig.files == null &&
          taskConfig.watched == null
        )
      ) {
        return watchedTaskNames;
      }

      const fileGlobs = taskConfig.watched || taskConfig.files;
      const globs = (Array.isArray(fileGlobs) ? fileGlobs : [fileGlobs])
        .map(glob => `${config.root}/${taskConfig.from}/${glob}`);

      chokidar.watch(globs, {ignoreInitial: true})
      .on('all', (evt, path) => changesQueue.push({taskName, evt, path}))
      .on('error', reject);

      return watchedTaskNames.concat(taskName);
    }, []);

    if (watchedTaskNames.length === 0) {
      resolve();
    }

    log(MESSAGES.watching(watchedTaskNames));

    setInterval(flushChangesQueue, 100);
  }));

  throws(await watchAndServe);
});
<commit_msg>Added second static listener to serve-basic-story for files referenced by sourcemaps (debug only).<commit_after>// Native
const {existsSync} = require('fs');
const {createServer} = require('http');

// External
const chokidar = require('chokidar');
const finalhandler = require('finalhandler');
const merge = require('merge');
const serveStatic = require('serve-static');

// Ours
const {pack, throws} = require('../../../utils/async');
const {log} = require('../../../utils');
const {exec} = require('../../../processes');
const {
  BUILD_DIR, D_KEY, DEFAULTS, KEY, TASK_NAMES
} = require('../build-basic-story/constants');
const build = require('../build-basic-story');
const {command} = require('../');
const {OPTIONS, USAGE, MESSAGES, HOSTNAME} = require('./constants');

module.exports = command({
  name: 'serve-basic-story',
  options: OPTIONS,
  usage: USAGE,
  configRequired: true
}, async function (argv, config) {
  const serveConfig = typeof config.serve === 'object' ? config.serve : {};
  const buildConfigKey = argv.debug ? D_KEY : KEY;

  const buildConfig = merge.recursive(true, DEFAULTS[buildConfigKey],
    typeof config[buildConfigKey] === 'object' ? config[buildConfigKey] : {}
  );

  throws(await build(argv.$));

  const serve = serveStatic(`${config.root}/${BUILD_DIR}`);
  const serveProject = argv.debug ? serveStatic(`${config.root}`) : null;

  const server = createServer((req, res) => {
    if (argv.debug && existsSync(`${config.root}${req.url}`)) {
      return serveProject(req, res, finalhandler(req, res));
    }

    serve(req, res, finalhandler(req, res));
  });
  const [, domain] = await exec(`awk '/^domain/ {print $2}' /etc/resolv.conf`);
  const hostname = `${HOSTNAME}${domain ? `.${domain.replace('\n', '')}` : ''}`;
  const port = serveConfig.port || 8000;

  server.listen(port);

  log(MESSAGES.server(hostname, port));

  const changesQueue = [];

  async function flushChangesQueue() {
    if (changesQueue.length === 0) {
      return;
    }

    while (changesQueue.length > 0) {
      const {taskName, evt, path} = changesQueue.shift();

      log(MESSAGES.watchEvent(taskName, evt, path.replace(config.root, '')));
      throws(await build(argv.$.concat(['--taskName', taskName])));
    }

    log(MESSAGES.STILL_WATCHING);
  }

  const watchAndServe = pack(new Promise((resolve, reject) => {
    const watchedTaskNames = TASK_NAMES.reduce((watchedTaskNames, taskName) => {
      const taskConfig = buildConfig[taskName];

      if (
        typeof taskConfig !== 'object' ||
        taskConfig.from == null ||
        (
          taskConfig.files == null &&
          taskConfig.watched == null
        )
      ) {
        return watchedTaskNames;
      }

      const fileGlobs = taskConfig.watched || taskConfig.files;
      const globs = (Array.isArray(fileGlobs) ? fileGlobs : [fileGlobs])
        .map(glob => `${config.root}/${taskConfig.from}/${glob}`);

      chokidar.watch(globs, {ignoreInitial: true})
      .on('all', (evt, path) => changesQueue.push({taskName, evt, path}))
      .on('error', reject);

      return watchedTaskNames.concat(taskName);
    }, []);

    if (watchedTaskNames.length === 0) {
      resolve();
    }

    log(MESSAGES.watching(watchedTaskNames));

    setInterval(flushChangesQueue, 100);
  }));

  throws(await watchAndServe);
});
<|endoftext|>