<commit_before>const supertest = require('supertest');
const assert = require('assert');
const path = require('path');
const fs = require('fs');
const app = require('../../index');
const utils = require('../../utils');

describe('Integration', function() {
  before(function() {
    app.apiDataPath = path.join(__dirname, '..', 'data');
  });

  it('HTTP GET call to a wrong address', function(done) {
    supertest(app.app)
      .get('/wrong')
      .expect(404)
      .end(done);
  });

  it('HTTP GET CORS call to a right address with JSON stubbed data', function(done) {
    supertest(app.app)
      .options('/call')
      .set('Origin', 'http://saray.example.com')
      .set('custom-header1', 'custom-value1')
      .set('custom-header2', 'custom-value2')
      .set('Access-Control-Request-Headers', 'custom-header1, custom-header2')
      .set('Access-Control-Request-Method', 'GET')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(
          response.headers['access-control-allow-headers'] === 'Origin, X-Requested-With, Content-Type, Accept, Authorization, custom-header1, custom-header2'
        );
        return done();
      });
  });

  it('HTTP GET call to a right address with JSON stubbed data', function(done) {
    supertest(app.app)
      .get('/call')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.key === 'value');
        return done();
      });
  });

  it('HTTP GET call to a right address with JS stubbed data', function(done) {
    supertest(app.app)
      .get('/call4')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.key === 'value');
        return done();
      });
  });

  it('HTTP GET call to a right address with parameters with JSON stubbed data', function(done) {
    supertest(app.app)
      .get('/call?param1=value1')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyWithParam === 'value');
        return done();
      });
  });

  it('HTTP GET call to a right address with parameters with JS stubbed data', function(done) {
    supertest(app.app)
      .get('/call4?param1=value1')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyWithParam === 'value');
        return done();
      });
  });

  it('HTTP GET call to a malformed JSON', function(done) {
    supertest(app.app)
      .get('/malformed')
      .expect(500)
      .end(done);
  });

  it('HTTP POST call to a wrong address', function(done) {
    supertest(app.app)
      .post('/wrong')
      .expect(404)
      .end(done);
  });

  it('HTTP POST call to a right address with JSON stubbed data', function(done) {
    supertest(app.app)
      .post('/call')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyPOST === 'value');
        return done();
      });
  });

  it('HTTP POST call to a right address with JS stubbed data', function(done) {
    supertest(app.app)
      .post('/call4')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyPOST === 'value');
        return done();
      });
  });

  it('HTTP POST call to a right address with parameters with JSON stubbed data', function(done) {
    supertest(app.app)
      .post('/call')
      .send({param1: 'value1'})
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyWithParamPOST === 'value');
        return done();
      });
  });

  it('HTTP POST call to a right address with parameters with JS stubbed data', function(done) {
    supertest(app.app)
      .post('/call4')
      .send({param1: 'value1'})
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyWithParamPOST === 'value');
        return done();
      });
  });

  it('HTTP POST call to a malformed JSON', function(done) {
    supertest(app.app)
      .post('/malformed')
      .expect(500)
      .end(done);
  });

  it('HTTP OPTIONS call to a wrong address', function(done) {
    supertest(app.app)
      .options('/generic/options')
      .expect(404)
      .end(done);
  });

  it('HTTP OPTIONS call to a right address with JSON stubbed data', function(done) {
    supertest(app.app)
      .options('/call')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP OPTIONS call to a right address with params with JSON stubbed data', function(done) {
    supertest(app.app)
      .options('/call2?param1=value1')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP OPTIONS call to a right address with params 2 with JSON stubbed data', function(done) {
    supertest(app.app)
      .options('/call3?param1=value1')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP OPTIONS call to a right address with JS stubbed data', function(done) {
    supertest(app.app)
      .options('/call4')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP OPTIONS call to a right address with params with JS stubbed data', function(done) {
    supertest(app.app)
      .options('/call5?param1=value1')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP OPTIONS call to a right address with params 2 with JS stubbed data', function(done) {
    supertest(app.app)
      .options('/call6?param1=value1')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });
});

describe('Integration with rootPath', function() {
  before(function() {
    app.apiDataPath = path.join(__dirname, '..', 'data');
    app.rootPath = '/saray/abc';
    app.app.use(app.rootPath, app.sarayRouter);
  });

  it('HTTP GET call to a wrong address', function(done) {
    supertest(app.app)
      .get('/saray/abc/wrong')
      .expect(404)
      .end(done);
  });

  it('HTTP GET CORS call to a right address with JSON stubbed data', function(done) {
    supertest(app.app)
      .options('/call')
      .set('Origin', 'http://saray.example.com')
      .set('custom-header1', 'custom-value1')
      .set('custom-header2', 'custom-value2')
      .set('Access-Control-Request-Headers', 'custom-header1, custom-header2')
      .set('Access-Control-Request-Method', 'GET')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(
          response.headers['access-control-allow-headers'] === 'Origin, X-Requested-With, Content-Type, Accept, Authorization, custom-header1, custom-header2'
        );
        return done();
      });
  });

  it('HTTP GET call to a right address with JSON stubbed data', function(done) {
    supertest(app.app)
      .get('/saray/abc/call')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.key === 'value');
        return done();
      });
  });

  it('HTTP GET call to a right address with JS stubbed data', function(done) {
    supertest(app.app)
      .get('/saray/abc/call4')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.key === 'value');
        return done();
      });
  });

  it('HTTP GET call to a right address with parameters with JSON stubbed data', function(done) {
    supertest(app.app)
      .get('/saray/abc/call?param1=value1')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyWithParam === 'value');
        return done();
      });
  });

  it('HTTP GET call to a right address with parameters with JS stubbed data', function(done) {
    supertest(app.app)
      .get('/saray/abc/call4?param1=value1')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyWithParam === 'value');
        return done();
      });
  });

  it('HTTP GET call to a malformed JSON', function(done) {
    supertest(app.app)
      .get('/saray/abc/malformed')
      .expect(500)
      .end(done);
  });

  it('HTTP POST call to a wrong address', function(done) {
    supertest(app.app)
      .post('/saray/abc/wrong')
      .expect(404)
      .end(done);
  });

  it('HTTP POST call to a right address with JSON stubbed data', function(done) {
    supertest(app.app)
      .post('/saray/abc/call')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyPOST === 'value');
        return done();
      });
  });

  it('HTTP POST call to a right address with JS stubbed data', function(done) {
    supertest(app.app)
      .post('/saray/abc/call4')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyPOST === 'value');
        return done();
      });
  });

  it('HTTP POST call to a right address with parameters with JSON stubbed data', function(done) {
    supertest(app.app)
      .post('/saray/abc/call')
      .send({param1: 'value1'})
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyWithParamPOST === 'value');
        return done();
      });
  });

  it('HTTP POST call to a right address with parameters with JS stubbed data', function(done) {
    supertest(app.app)
      .post('/call4')
      .send({param1: 'value1'})
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyWithParamPOST === 'value');
        return done();
      });
  });

  it('HTTP POST call to a malformed JSON', function(done) {
    supertest(app.app)
      .post('/saray/abc/malformed')
      .expect(500)
      .end(done);
  });

  it('HTTP OPTIONS call to a wrong address', function(done) {
    supertest(app.app)
      .options('/saray/abc/generic/options')
      .expect(404)
      .end(done);
  });

  it('HTTP OPTIONS call to a right address with JSON stubbed data', function(done) {
    supertest(app.app)
      .options('/saray/abc/call')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP OPTIONS call to a right address with params with JSON stubbed data', function(done) {
    supertest(app.app)
      .options('/saray/abc/call2?param1=value1')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP OPTIONS call to a right address with params 2 with JSON stubbed data', function(done) {
    supertest(app.app)
      .options('/saray/abc/call3?param1=value1')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP OPTIONS call to a right address with JS stubbed data', function(done) {
    supertest(app.app)
      .options('/saray/abc/call4')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP OPTIONS call to a right address with params with JS stubbed data', function(done) {
    supertest(app.app)
      .options('/saray/abc/call5?param1=value1')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP OPTIONS call to a right address with params 2 with JS stubbed data', function(done) {
    supertest(app.app)
      .options('/saray/abc/call6?param1=value1')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP GET call to a right address with JS stubbed data to an updated file', function(done) {
    supertest(app.app)
      .get('/saray/abc/call6')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.key, 'value');
        // return done();
      });

    const strippedPath = utils.stripRootPath(app.rootPath, '/saray/abc/call6');
    const filePath = path.join(app.apiDataPath, strippedPath + '.GET.js');
    const dataFile = fs.readFileSync(filePath);
    const dataFileContent = dataFile.toString();
    const dataFileContentReplaced = dataFileContent.replace('value', 'value2');
    fs.writeFileSync(filePath, dataFileContentReplaced);

    supertest(app.app)
      .get('/saray/abc/call6')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.equal(response.body.key, 'value2');

        const dataFileContentReplaced2 = dataFileContent.replace('value2', 'value');
        fs.writeFileSync(filePath, dataFileContentReplaced2);

        supertest(app.app)
          .get('/saray/abc/call6')
          .expect(200)
          .end(function(err, response) {
            assert.ok(!err);
            assert.equal(response.body.key, 'value');
            return done();
          });
      });
  });
});
<commit_msg>Refs #43 - Integration tests for JS stubbed data loaded first<commit_after>const supertest = require('supertest');
const assert = require('assert');
const path = require('path');
const fs = require('fs');
const app = require('../../index');
const utils = require('../../utils');

describe('Integration', function() {
  before(function() {
    app.apiDataPath = path.join(__dirname, '..', 'data');
  });

  it('HTTP GET call to a wrong address', function(done) {
    supertest(app.app)
      .get('/wrong')
      .expect(404)
      .end(done);
  });

  it('HTTP GET CORS call to a right address with JSON stubbed data', function(done) {
    supertest(app.app)
      .options('/call')
      .set('Origin', 'http://saray.example.com')
      .set('custom-header1', 'custom-value1')
      .set('custom-header2', 'custom-value2')
      .set('Access-Control-Request-Headers', 'custom-header1, custom-header2')
      .set('Access-Control-Request-Method', 'GET')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(
          response.headers['access-control-allow-headers'] === 'Origin, X-Requested-With, Content-Type, Accept, Authorization, custom-header1, custom-header2'
        );
        return done();
      });
  });

  it('HTTP GET call to a right address with JSON stubbed data', function(done) {
    supertest(app.app)
      .get('/call')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.key === 'value');
        return done();
      });
  });

  it('HTTP GET call to a right address with JS stubbed data', function(done) {
    supertest(app.app)
      .get('/call4')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.key === 'value');
        return done();
      });
  });

  it('HTTP GET call to a right address with parameters with JSON stubbed data', function(done) {
    supertest(app.app)
      .get('/call?param1=value1')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyWithParam === 'value');
        return done();
      });
  });

  it('HTTP GET call to a right address with parameters with JS stubbed data', function(done) {
    supertest(app.app)
      .get('/call4?param1=value1')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyWithParam === 'value');
        return done();
      });
  });

  it('HTTP GET call to a malformed JSON', function(done) {
    supertest(app.app)
      .get('/malformed')
      .expect(500)
      .end(done);
  });

  it('HTTP POST call to a wrong address', function(done) {
    supertest(app.app)
      .post('/wrong')
      .expect(404)
      .end(done);
  });

  it('HTTP POST call to a right address with JSON stubbed data', function(done) {
    supertest(app.app)
      .post('/call')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyPOST === 'value');
        return done();
      });
  });

  it('HTTP POST call to a right address with JS stubbed data', function(done) {
    supertest(app.app)
      .post('/call4')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyPOST === 'value');
        return done();
      });
  });

  it('HTTP POST call to a right address with parameters with JSON stubbed data', function(done) {
    supertest(app.app)
      .post('/call')
      .send({param1: 'value1'})
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyWithParamPOST === 'value');
        return done();
      });
  });

  it('HTTP POST call to a right address with parameters with JS stubbed data', function(done) {
    supertest(app.app)
      .post('/call4')
      .send({param1: 'value1'})
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyWithParamPOST === 'value');
        return done();
      });
  });

  it('HTTP POST call to a malformed JSON', function(done) {
    supertest(app.app)
      .post('/malformed')
      .expect(500)
      .end(done);
  });

  it('HTTP OPTIONS call to a wrong address', function(done) {
    supertest(app.app)
      .options('/generic/options')
      .expect(404)
      .end(done);
  });

  it('HTTP OPTIONS call to a right address with JSON stubbed data', function(done) {
    supertest(app.app)
      .options('/call')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP OPTIONS call to a right address with params with JSON stubbed data', function(done) {
    supertest(app.app)
      .options('/call2?param1=value1')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP OPTIONS call to a right address with params 2 with JSON stubbed data', function(done) {
    supertest(app.app)
      .options('/call3?param1=value1')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP OPTIONS call to a right address with JS stubbed data', function(done) {
    supertest(app.app)
      .options('/call4')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP OPTIONS call to a right address with params with JS stubbed data', function(done) {
    supertest(app.app)
      .options('/call5?param1=value1')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP OPTIONS call to a right address with params 2 with JS stubbed data', function(done) {
    supertest(app.app)
      .options('/call6?param1=value1')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP GET call to a right address with JS stubbed data that must be served first', function(done) {
    supertest(app.app)
      .get('/jsFirst')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.deepEqual(response.body.key, 'valueJS');
        return done();
      });
  });

  it('HTTP GET call to a right address with JS stubbed data that must be served first with parameters', function(done) {
    supertest(app.app)
      .get('/jsFirst?param1=valueParam')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.deepEqual(response.body.key, 'valueJSvalueParam');
        return done();
      });
  });
});

describe('Integration with rootPath', function() {
  before(function() {
    app.apiDataPath = path.join(__dirname, '..', 'data');
    app.rootPath = '/saray/abc';
    app.app.use(app.rootPath, app.sarayRouter);
  });

  it('HTTP GET call to a wrong address', function(done) {
    supertest(app.app)
      .get('/saray/abc/wrong')
      .expect(404)
      .end(done);
  });

  it('HTTP GET CORS call to a right address with JSON stubbed data', function(done) {
    supertest(app.app)
      .options('/call')
      .set('Origin', 'http://saray.example.com')
      .set('custom-header1', 'custom-value1')
      .set('custom-header2', 'custom-value2')
      .set('Access-Control-Request-Headers', 'custom-header1, custom-header2')
      .set('Access-Control-Request-Method', 'GET')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(
          response.headers['access-control-allow-headers'] === 'Origin, X-Requested-With, Content-Type, Accept, Authorization, custom-header1, custom-header2'
        );
        return done();
      });
  });

  it('HTTP GET call to a right address with JSON stubbed data', function(done) {
    supertest(app.app)
      .get('/saray/abc/call')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.key === 'value');
        return done();
      });
  });

  it('HTTP GET call to a right address with JS stubbed data', function(done) {
    supertest(app.app)
      .get('/saray/abc/call4')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.key === 'value');
        return done();
      });
  });

  it('HTTP GET call to a right address with parameters with JSON stubbed data', function(done) {
    supertest(app.app)
      .get('/saray/abc/call?param1=value1')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyWithParam === 'value');
        return done();
      });
  });

  it('HTTP GET call to a right address with parameters with JS stubbed data', function(done) {
    supertest(app.app)
      .get('/saray/abc/call4?param1=value1')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyWithParam === 'value');
        return done();
      });
  });

  it('HTTP GET call to a malformed JSON', function(done) {
    supertest(app.app)
      .get('/saray/abc/malformed')
      .expect(500)
      .end(done);
  });

  it('HTTP POST call to a wrong address', function(done) {
    supertest(app.app)
      .post('/saray/abc/wrong')
      .expect(404)
      .end(done);
  });

  it('HTTP POST call to a right address with JSON stubbed data', function(done) {
    supertest(app.app)
      .post('/saray/abc/call')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyPOST === 'value');
        return done();
      });
  });

  it('HTTP POST call to a right address with JS stubbed data', function(done) {
    supertest(app.app)
      .post('/saray/abc/call4')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyPOST === 'value');
        return done();
      });
  });

  it('HTTP POST call to a right address with parameters with JSON stubbed data', function(done) {
    supertest(app.app)
      .post('/saray/abc/call')
      .send({param1: 'value1'})
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyWithParamPOST === 'value');
        return done();
      });
  });

  it('HTTP POST call to a right address with parameters with JS stubbed data', function(done) {
    supertest(app.app)
      .post('/call4')
      .send({param1: 'value1'})
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.keyWithParamPOST === 'value');
        return done();
      });
  });

  it('HTTP POST call to a malformed JSON', function(done) {
    supertest(app.app)
      .post('/saray/abc/malformed')
      .expect(500)
      .end(done);
  });

  it('HTTP OPTIONS call to a wrong address', function(done) {
    supertest(app.app)
      .options('/saray/abc/generic/options')
      .expect(404)
      .end(done);
  });

  it('HTTP OPTIONS call to a right address with JSON stubbed data', function(done) {
    supertest(app.app)
      .options('/saray/abc/call')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP OPTIONS call to a right address with params with JSON stubbed data', function(done) {
    supertest(app.app)
      .options('/saray/abc/call2?param1=value1')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP OPTIONS call to a right address with params 2 with JSON stubbed data', function(done) {
    supertest(app.app)
      .options('/saray/abc/call3?param1=value1')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP OPTIONS call to a right address with JS stubbed data', function(done) {
    supertest(app.app)
      .options('/saray/abc/call4')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP OPTIONS call to a right address with params with JS stubbed data', function(done) {
    supertest(app.app)
      .options('/saray/abc/call5?param1=value1')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP OPTIONS call to a right address with params 2 with JS stubbed data', function(done) {
    supertest(app.app)
      .options('/saray/abc/call6?param1=value1')
      .expect(200)
      .end(function(err) {
        assert.ok(!err);
        return done();
      });
  });

  it('HTTP GET call to a right address with JS stubbed data to an updated file', function(done) {
    supertest(app.app)
      .get('/saray/abc/call6')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.ok(response.body.key, 'value');
        // return done();
      });

    const strippedPath = utils.stripRootPath(app.rootPath, '/saray/abc/call6');
    const filePath = path.join(app.apiDataPath, strippedPath + '.GET.js');
    const dataFile = fs.readFileSync(filePath);
    const dataFileContent = dataFile.toString();
    const dataFileContentReplaced = dataFileContent.replace('value', 'value2');
    fs.writeFileSync(filePath, dataFileContentReplaced);

    supertest(app.app)
      .get('/saray/abc/call6')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.equal(response.body.key, 'value2');

        const dataFileContentReplaced2 = dataFileContent.replace('value2', 'value');
        fs.writeFileSync(filePath, dataFileContentReplaced2);

        supertest(app.app)
          .get('/saray/abc/call6')
          .expect(200)
          .end(function(err, response) {
            assert.ok(!err);
            assert.equal(response.body.key, 'value');
            return done();
          });
      });
  });

  it('HTTP GET call to a right address with JS stubbed data that must be served first', function(done) {
    supertest(app.app)
      .get('/saray/abc/jsFirst')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.deepEqual(response.body.key, 'valueJS');
        return done();
      });
  });

  it('HTTP GET call to a right address with JS stubbed data that must be served first with parameters', function(done) {
    supertest(app.app)
      .get('/saray/abc/jsFirst?param1=valueParam')
      .expect(200)
      .end(function(err, response) {
        assert.ok(!err);
        assert.deepEqual(response.body.key, 'valueJSvalueParam');
        return done();
      });
  });
});
<|endoftext|>


<commit_before>angular.module("static-include", []).directive('staticInclude', function($templateRequest, $compile) {
  return {
    restrict: 'A',
    transclude: true,
    replace: true,
    scope: false,
    link: function($scope, element, attrs, ctrl, transclude) {
      var templatePath = attrs.staticInclude;

      try{
        templatePath = $scope.$eval(templatePath);
      }catch(err){
        throw new Error(attrs.staticInclude+' is not a valid object');
      }

      $templateRequest(templatePath)
        .then(function(response) {
          var contents = element.html(response).contents();
          $compile(contents)($scope.$new(false, $scope.$parent));
        });
    }
  };
});
<commit_msg>Removing unnecessary eval<commit_after>angular.module("static-include", []).directive('staticInclude', function($templateRequest, $compile) {
  return {
    restrict: 'A',
    transclude: true,
    replace: true,
    scope: false,
    link: function($scope, element, attrs, ctrl, transclude) {
      var templatePath = attrs.staticInclude;

      $templateRequest(templatePath)
        .then(function(response) {
          var contents = element.html(response).contents();
          $compile(contents)($scope.$new(false, $scope.$parent));
        });
    }
  };
});
<|endoftext|>


<commit_before>// @flow

import {Platform} from 'react-native'
import {
	createBottomTabNavigator,
	NavigationScreenRouteConfig,
} from 'react-navigation'
import * as c from '../colors'
import {createMaterialBottomTabNavigator} from 'react-navigation-material-bottom-tabs'

type ComponentType = (
	screens: {[key: string]: NavigationScreenRouteConfig},
	options: any, // I don't know how to type this better…
	// the package provides a bunch of types… but it doesn't even use some
	// of them??? and none seem to be the combination of args to the second
	// arg of TabNavigator.
) => typeof createTabNavigator

const createTabNavigator =
	Platform.OS === 'android'
		? createMaterialBottomTabNavigator
		: createBottomTabNavigator

export const TabNavigator: ComponentType = (screens, options = {}) =>
	createTabNavigator(screens, {
		backBehavior: 'none',
		lazy: true,
		activeTintColor: c.black,
		inactiveTintColor: c.black25Percent,
		tabBarOptions: {
			...(options.tabBarOptions || {}),
			labelStyle: {
				...Platform.select({
					ios: {
						fontFamily: 'System',
					},
					android: {
						fontFamily: 'sans-serif-condensed',
						fontSize: 14,
					},
				}),
			},
		},
		...options,
	})
<commit_msg>Set theme<commit_after>// @flow

import {Platform} from 'react-native'
import {
	createBottomTabNavigator,
	NavigationScreenRouteConfig,
} from 'react-navigation'
import * as c from '../colors'
import {createMaterialBottomTabNavigator} from 'react-navigation-material-bottom-tabs'

type ComponentType = (
	screens: {[key: string]: NavigationScreenRouteConfig},
	options: any, // I don't know how to type this better…
	// the package provides a bunch of types… but it doesn't even use some
	// of them??? and none seem to be the combination of args to the second
	// arg of TabNavigator.
) => typeof createTabNavigator

const createTabNavigator =
	Platform.OS === 'android'
		? createMaterialBottomTabNavigator
		: createBottomTabNavigator

export const TabNavigator: ComponentType = (screens, options = {}) =>
	createTabNavigator(screens, {
		backBehavior: 'none',
		lazy: true,
		activeTintColor: c.black,
		inactiveTintColor: c.black25Percent,
		theme: {
			colors: {
				primary: c.olevilleGold,
			},
		},
		tabBarOptions: {
			...(options.tabBarOptions || {}),
			labelStyle: {
				...Platform.select({
					ios: {
						fontFamily: 'System',
					},
					android: {
						fontFamily: 'sans-serif-condensed',
						fontSize: 14,
					},
				}),
			},
		},
		...options,
	})
<|endoftext|>


<commit_before>import coreUtils from '@opentripplanner/core-utils'
import React, { Component } from 'react'
import { Button } from 'react-bootstrap'
import { connect } from 'react-redux'
import styled from 'styled-components'

import * as uiActions from '../../actions/ui'
import Map from '../map/map'
import Icon from '../narrative/icon'
import NarrativeItineraries from '../narrative/narrative-itineraries'
import {
  getActiveItineraries,
  getActiveSearch,
  getResponsesWithErrors
} from '../../util/state'

import MobileContainer from './container'
import ResultsError from './results-error'
import ResultsHeader from './results-header'

const StyledMobileContainer = styled(MobileContainer)`
  .options > .header {
    margin: 10px;
  }

  &.otp.mobile .mobile-narrative-container {
    bottom: 0;
    left: 0;
    overflow-y: auto;
    padding: 0;
    position: fixed;
    right: 0;
  }
`

const ExpandMapButton = styled(Button)`
  bottom: 10px;
  left: 10px;
  position: absolute;
  z-index: 999999;
`

const VIEW = uiActions.ItineraryView

const NARRATIVE_SPLIT_TOP_PERCENT = 45

/**
 * This component renders the mobile view of itinerary results from batch routing,
 * and features a split view between the map and itinerary results or narratives.
 */
class BatchMobileResultsScreen extends Component {
  componentDidUpdate (prevProps) {
    if (this.props.activeLeg !== prevProps.activeLeg) {
      // Check if the active leg has changed. If a different leg is selected,
      // unexpand the itinerary to show the map focused on the selected leg
      // (similar to the behavior of LineItinerary).
      this._setItineraryExpanded(false)
    }
  }

  _setItineraryExpanded = itineraryExpanded => {
    this.props.setItineraryView(itineraryExpanded ? VIEW.FULL : VIEW.SPLIT)
  }

  _toggleMapExpanded = () => {
    this.props.setItineraryView(this.props.itineraryView === VIEW.HIDDEN ? VIEW.SPLIT : VIEW.HIDDEN)
  }

  render () {
    const { errors, itineraries, itineraryView } = this.props
    const hasNoResult = itineraries.length === 0 && errors.length > 0
    const mapExpanded = itineraryView === VIEW.HIDDEN
    const itineraryExpanded = itineraryView === VIEW.FULL
    const narrativeTop = mapExpanded ? '100%' : (itineraryExpanded ? '100px' : `${NARRATIVE_SPLIT_TOP_PERCENT}%`)
    const mapBottom = mapExpanded ? 0 : `${100 - NARRATIVE_SPLIT_TOP_PERCENT}%`

    return (
      <StyledMobileContainer>
        <ResultsHeader />
        <div
          className='results-map'
          style={{bottom: mapBottom, display: itineraryExpanded ? 'none' : 'inherit'}}
        >
          <Map />
          <ExpandMapButton
            bsSize='small'
            onClick={this._toggleMapExpanded}
          >
            <Icon name={mapExpanded ? 'list-ul' : 'arrows-alt'} />{' '}
            {mapExpanded ? 'Show results' : 'Expand map'}
          </ExpandMapButton>
        </div>
        {hasNoResult
          ? <ResultsError
            error={errors[0]}
            style={{
              display: mapExpanded ? 'none' : 'inherit',
              top: narrativeTop,
              transition: 'top 300ms'
            }} />
          : (
            <div
              className='mobile-narrative-container'
              style={{top: narrativeTop, transition: 'top 300ms'}}
            >
              <NarrativeItineraries
                containerStyle={{
                  background: '#fff',
                  display: 'flex',
                  flexDirection: 'column',
                  height: '100%',
                  width: '100%'
                }}
              />
            </div>
          )
        }
      </StyledMobileContainer>
    )
  }
}

// connect to the redux store

const mapStateToProps = (state, ownProps) => {
  const activeSearch = getActiveSearch(state.otp)
  const urlParams = coreUtils.query.getUrlParams()

  return {
    activeLeg: activeSearch ? activeSearch.activeLeg : null,
    errors: getResponsesWithErrors(state.otp),
    itineraries: getActiveItineraries(state.otp),
    itineraryView: urlParams.ui_itineraryView
  }
}

const mapDispatchToProps = {
  setItineraryView: uiActions.setItineraryView
}

export default connect(mapStateToProps, mapDispatchToProps)(BatchMobileResultsScreen)
<commit_msg>refactor(BatchResultsScreen): Add uncommited refactors from 7c82cd7<commit_after>import coreUtils from '@opentripplanner/core-utils'
import React, { Component } from 'react'
import { Button } from 'react-bootstrap'
import { connect } from 'react-redux'
import styled from 'styled-components'

import * as uiActions from '../../actions/ui'
import Map from '../map/map'
import Icon from '../narrative/icon'
import NarrativeItineraries from '../narrative/narrative-itineraries'
import {
  getActiveItineraries,
  getActiveSearch,
  getResponsesWithErrors
} from '../../util/state'

import MobileContainer from './container'
import ResultsError from './results-error'
import ResultsHeader from './results-header'

const StyledMobileContainer = styled(MobileContainer)`
  .options > .header {
    margin: 10px;
  }

  &.otp.mobile .mobile-narrative-container {
    bottom: 0;
    left: 0;
    overflow-y: auto;
    padding: 0;
    position: fixed;
    right: 0;
  }
`

const ExpandMapButton = styled(Button)`
  bottom: 10px;
  left: 10px;
  position: absolute;
  z-index: 999999;
`

const VIEW = uiActions.ItineraryView

const NARRATIVE_SPLIT_TOP_PERCENT = 45

/**
 * This component renders the mobile view of itinerary results from batch routing,
 * and features a split view between the map and itinerary results or narratives.
 */
class BatchMobileResultsScreen extends Component {
  componentDidUpdate (prevProps) {
    if (this.props.activeLeg !== prevProps.activeLeg) {
      // Check if the active leg has changed. If a different leg is selected,
      // unexpand the itinerary to show the map focused on the selected leg
      // (similar to the behavior of LineItinerary).
      this._setItineraryExpanded(false)
    }
  }

  _setItineraryExpanded = itineraryExpanded => {
    this.props.setItineraryView(itineraryExpanded ? VIEW.FULL : VIEW.LIST)
  }

  _toggleMapExpanded = () => {
    this.props.setItineraryView(this.props.itineraryView === VIEW.HIDDEN ? VIEW.LIST : VIEW.HIDDEN)
  }

  render () {
    const { errors, itineraries, itineraryView } = this.props
    const hasNoResult = itineraries.length === 0 && errors.length > 0
    const mapExpanded = itineraryView === VIEW.HIDDEN
    const itineraryExpanded = itineraryView === VIEW.FULL
    const narrativeTop = mapExpanded ? '100%' : (itineraryExpanded ? '100px' : `${NARRATIVE_SPLIT_TOP_PERCENT}%`)
    const mapBottom = mapExpanded ? 0 : `${100 - NARRATIVE_SPLIT_TOP_PERCENT}%`

    return (
      <StyledMobileContainer>
        <ResultsHeader />
        <div
          className='results-map'
          style={{bottom: mapBottom, display: itineraryExpanded ? 'none' : 'inherit'}}
        >
          <Map />
          <ExpandMapButton
            bsSize='small'
            onClick={this._toggleMapExpanded}
          >
            <Icon name={mapExpanded ? 'list-ul' : 'arrows-alt'} />{' '}
            {mapExpanded ? 'Show results' : 'Expand map'}
          </ExpandMapButton>
        </div>
        {hasNoResult
          ? <ResultsError
            error={errors[0]}
            style={{
              display: mapExpanded ? 'none' : 'inherit',
              top: narrativeTop,
              transition: 'top 300ms'
            }} />
          : (
            <div
              className='mobile-narrative-container'
              style={{top: narrativeTop, transition: 'top 300ms'}}
            >
              <NarrativeItineraries
                containerStyle={{
                  background: '#fff',
                  display: 'flex',
                  flexDirection: 'column',
                  height: '100%',
                  width: '100%'
                }}
              />
            </div>
          )
        }
      </StyledMobileContainer>
    )
  }
}

// connect to the redux store

const mapStateToProps = (state, ownProps) => {
  const activeSearch = getActiveSearch(state.otp)
  const urlParams = coreUtils.query.getUrlParams()

  return {
    activeLeg: activeSearch ? activeSearch.activeLeg : null,
    errors: getResponsesWithErrors(state.otp),
    itineraries: getActiveItineraries(state.otp),
    itineraryView: urlParams.ui_itineraryView
  }
}

const mapDispatchToProps = {
  setItineraryView: uiActions.setItineraryView
}

export default connect(mapStateToProps, mapDispatchToProps)(BatchMobileResultsScreen)
<|endoftext|>


<commit_before>import mongoose from 'mongoose';
import * as Q from 'q';
mongoose.Promise = Q.Promise;
import ListItem from './listItem';
import ListTemplate from './listTemplate';
import PendingItem from './pendingItem';
const Schema = mongoose.Schema;
import * as _ from 'lodash';

const LIST_THRESHOLD = 1;

const listSchema = new Schema({
  cuid: { type: 'String', required: true },
  verb: { type: 'String', required: true },
  action: { type: 'String', required: true },
  _template: { type: Schema.Types.ObjectId, ref: 'ListTemplate' },
  items: [ListItem.schema],
  _users: [{ type: Schema.Types.ObjectId, ref: 'User' }],
  dateAdded: { type: 'Date', default: Date.now, required: true },
  dateModified: { type: 'Date', default: Date.now, required: false },
});

listSchema.virtual('name').get( function() {
  return `${this.verb} every ${this.action}`;
});

listSchema.virtual('percentComplete').get( function() {
  const numItems = this.items.length;
  const numComplete = _.filter(this.items, 'complete').length;
  return _.round(numComplete*100/numItems) || 0;
});

listSchema.query.forUser = function(user) {
  return this.find({_users: user._id});
};

listSchema.methods.addListItem = function(item, user) {
  let list = this;

  //add item to this list no matter what
  const newItem = new ListItem({text: item});
  list.items.push(newItem);

  //find listtemplate
  return ListTemplate.findOne({_id: this._template}).exec()
    .then((template) => {

      //if there is no template
      // don't do anything else
      if(!template) {
        return Q.reject('no template');
      }

      //if the template was created by the current user
      // bypass the threshold and add it to everything immediately
      if(template.createdBy && user._id.equals(template.createdBy)) {
        return template.addItemToLists(item, [list._id]);
      }

      //find the pending item with that text
      const lowercaseText = _.toLower(item);
      const pendingItem = _.find(template.pendingItems, {text: lowercaseText});

      //if there is no pending item, create one, then do nothing
      if(!pendingItem) {
        template.pendingItems.push(new PendingItem({text: lowercaseText, _lists: [list._id]}));
        return template.save();
      }
      //what if pending items already includes this list?
      // do nothing

      else if(_.find(pendingItem._lists, o => o.equals(list._id))){
        //don't even save the list - item is a dupe
        return Q.reject('This list already contains this item.');
      }
      //if we have less than the threshold, just add the list id
      else if(pendingItem._lists.length < LIST_THRESHOLD) {
        pendingItem._lists.push(list._id);
        return pendingItem.save();
      }
      //we've met the threshold, add the item to the template
      // and update all the lists
      else {
        //add the list id anyway so that we don't
        // double-add the item
        pendingItem._lists.push(list._id);
        return template.realizePendingItem(pendingItem);
      }
    })
    .then( () => {
      return list.save();
    })
    .then( (newList) => {
      return newList;
    })
    .catch( (err) => {
      console.log(err);
      return Q.reject(err);
    });
};

listSchema.methods.addItemsFromTemplate = function(template, cb) {
  this.items = _.clone(template.items);
  this._template = template._id;
  return this.save(cb);
};

listSchema.methods.addItemToOtherLists = function(itemText) {

  this.constructor.find({_template: this._template, _id: { $ne: this._id }}).exec()
    .then( (lists) => {
      lists.forEach( (list) => {
        list.items.push(new ListItem({text: itemText}));
        list.save();
      });
    });
};

listSchema.statics.demoLists = function() {
  return [
    {name: 'watch every Harry Potter movie'},
    {name: 'visit every castle in Scotland'},
    {name: 'read every Stephen King novel'},
    {name: 'run a 5k in every US state'},
    {name: 'visit every country in Europe'}
  ];
};

listSchema.set('toJSON', { virtuals: true });

export default mongoose.model('List', listSchema);
<commit_msg>error message for dupes<commit_after>import mongoose from 'mongoose';
import * as Q from 'q';
mongoose.Promise = Q.Promise;
import ListItem from './listItem';
import ListTemplate from './listTemplate';
import PendingItem from './pendingItem';
const Schema = mongoose.Schema;
import * as _ from 'lodash';

const LIST_THRESHOLD = 1;

const listSchema = new Schema({
  cuid: { type: 'String', required: true },
  verb: { type: 'String', required: true },
  action: { type: 'String', required: true },
  _template: { type: Schema.Types.ObjectId, ref: 'ListTemplate' },
  items: [ListItem.schema],
  _users: [{ type: Schema.Types.ObjectId, ref: 'User' }],
  dateAdded: { type: 'Date', default: Date.now, required: true },
  dateModified: { type: 'Date', default: Date.now, required: false },
});

listSchema.virtual('name').get( function() {
  return `${this.verb} every ${this.action}`;
});

listSchema.virtual('percentComplete').get( function() {
  const numItems = this.items.length;
  const numComplete = _.filter(this.items, 'complete').length;
  return _.round(numComplete*100/numItems) || 0;
});

listSchema.query.forUser = function(user) {
  return this.find({_users: user._id});
};

listSchema.methods.addListItem = function(item, user) {
  let list = this;

  if (_.find(list.items, (i) => _.toLower(i.text) === _.toLower(item))) {
    return Q.reject(`This list already contains ${item}`);
  }

  //add item to this list no matter what
  const newItem = new ListItem({text: item});
  list.items.push(newItem);

  //find listtemplate
  return ListTemplate.findOne({_id: this._template}).exec()
    .then((template) => {

      //if there is no template
      // don't do anything else
      if(!template) {
        return Q.reject('no template');
      }

      //if the template was created by the current user
      // bypass the threshold and add it to everything immediately
      if(template.createdBy && user._id.equals(template.createdBy)) {
        return template.addItemToLists(item, [list._id]);
      }

      //find the pending item with that text
      const lowercaseText = _.toLower(item);
      const pendingItem = _.find(template.pendingItems, {text: lowercaseText});

      //if there is no pending item, create one, then do nothing
      if(!pendingItem) {
        template.pendingItems.push(new PendingItem({text: lowercaseText, _lists: [list._id]}));
        return template.save();
      }
      //what if pending items already includes this list?
      // do nothing

      else if(_.find(pendingItem._lists, o => o.equals(list._id))){
        //don't even save the list - item is a dupe
        return Q.reject('This list already contains this item.');
      }
      //if we have less than the threshold, just add the list id
      else if(pendingItem._lists.length < LIST_THRESHOLD) {
        pendingItem._lists.push(list._id);
        return pendingItem.save();
      }
      //we've met the threshold, add the item to the template
      // and update all the lists
      else {
        //add the list id anyway so that we don't
        // double-add the item
        pendingItem._lists.push(list._id);
        return template.realizePendingItem(pendingItem);
      }
    })
    .then( () => {
      return list.save();
    })
    .then( (newList) => {
      return newList;
    })
    .catch( (err) => {
      console.log(err);
      return Q.reject(err);
    });
};

listSchema.methods.addItemsFromTemplate = function(template, cb) {
  this.items = _.clone(template.items);
  this._template = template._id;
  return this.save(cb);
};

listSchema.methods.addItemToOtherLists = function(itemText) {

  this.constructor.find({_template: this._template, _id: { $ne: this._id }}).exec()
    .then( (lists) => {
      lists.forEach( (list) => {
        list.items.push(new ListItem({text: itemText}));
        list.save();
      });
    });
};

listSchema.statics.demoLists = function() {
  return [
    {name: 'watch every Harry Potter movie'},
    {name: 'visit every castle in Scotland'},
    {name: 'read every Stephen King novel'},
    {name: 'run a 5k in every US state'},
    {name: 'visit every country in Europe'},
    {name: 'visit every continent'}
  ];
};

listSchema.set('toJSON', { virtuals: true });

export default mongoose.model('List', listSchema);
<|endoftext|>


<commit_before>var
    esPhinx,
    Constructor,
    window;

(function($module) {
    "use strict";

    const
        CSS_CLASS = "esphinx ui",
        CSS_CLASS_QUERY = "." + CSS_CLASS.replace(/ +/g, ".");

    $module.extend({

        selectors: {

            Select: {

                new: function(select, options) {
                    var
                        $ = esPhinx,
                        ConstructionClass = $module.selectors.Select,
                        wrapper = $("

"),
                        caption = $("

"),
                        optionsPanel = $("

"),
                        searchTextBox = $("<input></input>"),
                        abstractSelect = $("

"),
                        abstractOptions = [],
                        captionText = $("

"),
                        selectElement = $(select),
                        optionElements = selectElement.find("option"),

                        Option = {
                            new: function(data) {
                                var
                                    option,
                                    abstractOption,
                                    ConstructionClass = Option.new,
                                    select = $(data.select),

                                    buildAbstractOption = function(li,
                                                                    option) {
                                        li = $(li);
                                        option = $(option);
                                        li.text(option.text());
                                        li.attribute("data-value", option
                                                     .attribute("value"));
                                    };

                                if (!(this instanceof ConstructionClass)) {
                                    return new (Constructor
                                                .new(ConstructionClass,
                                                     arguments))();
                                }

                                this.append = function() {
                                    if (abstractOption.tagName() != "option") {
                                        data.abstractSelect
                                            .append(abstractOption);
                                    }
                                };

                                this.select = function() {
                                    $(data.captionText).text($(abstractOption)
                                                             .textContent());
                                    select.find("option:checked")
                                        .unselect();
                                    option.select();
                                    $(data.optionsPanel).hide();
                                    toggleCaptionClass(data.caption);
                                };

                                this.element = function() {
                                    return abstractOption;
                                };

                                if ($(data.option).tagName() == "option") {
                                    option = $(data.option);
                                    abstractOption = $("

");
                                    buildAbstractOption(abstractOption, option);
                                    this.append();
                                } else {
                                    abstractOption = $(data.option);
                                    option = select
                                        .find("option[value='" +
                                              abstractOption.data("value") +
                                              "']");
                                }
                            }
                        },

                        selected = function(select) {
                            return $(select).find("option:checked");
                        },

                        toggleCaptionClass = function(caption) {
                            caption.toggleClass("arrow-expanded",
                                "arrow-retracted");
                        },

                        decorate = function() {
                            selectElement.hide();

                            wrapper.insertAfter(selectElement);
                            captionText.text(selected(selectElement).text());
                            caption.append(captionText);
                            wrapper.prepend(caption);
                            wrapper.append(optionsPanel);
                            optionsPanel.append(abstractSelect);

                            var
                                bindFoundListEventListener = function(
                                    abstractOptions) {
                                    abstractOptions
                                        .forEach(function(abstractOption) {
                                        $(abstractOption.element()).on("click",
                                            function() {
                                            abstractOption.select();
                                        });
                                    });
                                },

                                decorateOptions = function(optionElements) {
                                    optionElements.each(function(option) {
                                        option = Option.new({
                                            option: option,
                                            select: selectElement,
                                            caption: caption,
                                            captionText: captionText,
                                            optionsPanel: optionsPanel,
                                            abstractSelect: abstractSelect
                                        });

                                        abstractOptions.push(option);
                                    });

                                    bindFoundListEventListener(abstractOptions);
                                    abstractOptions = [];
                                },

                                decorateSearchTextBox = function() {
                                    searchTextBox.attribute("type", "text");
                                    optionsPanel.prepend(searchTextBox);

                                    $.ui.panels.autocomplete
                                        .new(searchTextBox, abstractSelect, {
                                        order: options.order
                                    }, function(found) {
                                        decorateOptions(found);
                                    });

                                };

                            wrapper.addClass(CSS_CLASS + " select");
                            caption.addClass("caption arrow-retracted");
                            optionsPanel.addClass("options-panel");
                            captionText.addClass("text");

                            // toggle on click on caption
                            caption.on("click", function() {
                                optionsPanel.toggle();
                                toggleCaptionClass($(this));
                            });

                            if (typeof options.searchTextBox == "boolean" &&
                                options.searchTextBox) {
                                decorateSearchTextBox();
                            }

                            decorateOptions(optionElements);
                        };

                    if (!(this instanceof ConstructionClass.new)) {
                        return new ConstructionClass
                            .new($(select), options);
                    }

                    decorate();

                    $(window.document).on("click", function(e) {
                        var
                            wrapper = $(CSS_CLASS_QUERY + ".select"),
                            optionsPanels = wrapper
                                .find(".options-panel"),
                            captions = wrapper.find(".caption");

                        if (!$(e.target).parent(CSS_CLASS_QUERY +
                                                ".select").some()) {
                            if (optionsPanels.visible()) {
                                optionsPanels.hide();
                                captions.removeClass("arrow-expanded");
                                captions.addClass("arrow-retracted");
                            }

                        }
                    });

                    this.addOption = function(option) {
                        // testar se existe no select antes de adicioná-la a ele
                        if (select.includes(option)) {

                        } else {

                        }
                    };

                    return this;
                }

            }

        }

    });

}(esPhinx.ui));
<commit_msg>reorganize Select<commit_after>var
    esPhinx,
    Constructor,
    Extensor;

(function($, $module) {
    "use strict";

    const
        CSS_CLASS = "esphinx ui",
        CSS_CLASS_QUERY = "." + CSS_CLASS.replace(/ +/g, ".");

    $module.extend({
        selectors: {Select: {}}
    });

    Extensor.new($module.selectors.Select, true, {
        new: function(select, options) {
            var
                $ = esPhinx,
                ConstructionClass = $module.selectors.Select,
                wrapper = $("

"),
                caption = $("

"),
                optionsPanel = $("

"),
                searchTextBox = $("<input></input>"),
                abstractSelect = $("

"),
                abstractOptions = [],
                captionText = $("

"),
                selectElement = $(select),
                optionElements = selectElement.find("option"),

                Option = {
                    new: function(data) {
                        var
                            option,
                            abstractOption,
                            ConstructionClass = Option.new,
                            select = $(data.select),

                            buildAbstractOption = function(li, option) {
                                li = $(li);
                                option = $(option);
                                li.text(option.text());
                                li.attribute("data-value", option
                                             .attribute("value"));
                            };

                        if (!(this instanceof ConstructionClass)) {
                            return new (Constructor.new(ConstructionClass,
                                                        arguments))();
                        }

                        this.append = function() {
                            if (abstractOption.tagName() != "option") {
                                data.abstractSelect.append(abstractOption);
                            }
                        };

                        this.select = function() {
                            $(data.captionText).text($(abstractOption)
                                                     .textContent());
                            select.find("option:checked").unselect();
                            option.select();
                            $(data.optionsPanel).hide();
                            toggleCaptionClass(data.caption);
                        };

                        this.element = function() {
                            return abstractOption;
                        };

                        if ($(data.option).tagName() == "option") {
                            option = $(data.option);
                            abstractOption = $("

");
                            buildAbstractOption(abstractOption, option);
                            this.append();
                        } else {
                            abstractOption = $(data.option);
                            option = select.find("option[value='" +
                                      abstractOption.data("value") + "']");
                        }
                    }
                },

                selected = function(select) {
                    return $(select).find("option:checked");
                },

                toggleCaptionClass = function(caption) {
                    caption.toggleClass("arrow-expanded", "arrow-retracted");
                },

                decorate = function() {
                    selectElement.hide();
                    wrapper.insertAfter(selectElement);
                    captionText.text(selected(selectElement).text());
                    caption.append(captionText);
                    wrapper.prepend(caption);
                    wrapper.append(optionsPanel);
                    optionsPanel.append(abstractSelect);

                    var
                        attachEventListenerOnFoundList = function(
                            abstractOptions) {
                            abstractOptions.forEach(function(abstractOption) {
                                $(abstractOption.element()).on("click",
                                                               function() {
                                    abstractOption.select();
                                });
                            });
                        },

                        decorateOptions = function(optionElements) {
                            optionElements.each(function(option) {
                                option = Option.new({
                                    option: option,
                                    select: selectElement,
                                    caption: caption,
                                    captionText: captionText,
                                    optionsPanel: optionsPanel,
                                    abstractSelect: abstractSelect
                                });

                                abstractOptions.push(option);
                            });

                            attachEventListenerOnFoundList(abstractOptions);
                            abstractOptions = [];
                        },

                        decorateSearchTextBox = function() {
                            searchTextBox.attribute("type", "text");
                            optionsPanel.prepend(searchTextBox);

                            $.ui.panels.autocomplete.new(searchTextBox,
                                                         abstractSelect, {
                                order: options.order
                            }, function(found) {
                                decorateOptions(found);
                            });

                        };

                    wrapper.addClass(CSS_CLASS + " select");
                    caption.addClass("caption arrow-retracted");
                    optionsPanel.addClass("options-panel");
                    captionText.addClass("text");

                    // toggle on click on caption
                    caption.on("click", function() {
                        optionsPanel.toggle();
                        toggleCaptionClass($(this));
                    });

                    if (typeof options.searchTextBox == "boolean" &&
                        options.searchTextBox) {
                        decorateSearchTextBox();
                    }

                    decorateOptions(optionElements);
                };

            if (!(this instanceof ConstructionClass.new)) {
                return new ConstructionClass.new($(select), options);
            }

            decorate();

            $(window.document).on("click", function(e) {
                var
                    wrapper = $(CSS_CLASS_QUERY + ".select"),
                    optionsPanels = wrapper.find(".options-panel"),
                    captions = wrapper.find(".caption");

                if (!$(e.target).parent(CSS_CLASS_QUERY + ".select").some()) {
                    if (optionsPanels.visible()) {
                        optionsPanels.hide();
                        captions.removeClass("arrow-expanded");
                        captions.addClass("arrow-retracted");
                    }
                }
            });

            this.addOption = function(option) {
                // testar se existe no select antes de adicioná-la a ele
                if (select.includes(option)) {

                } else {

                }
            };

            return this;
        }
    });

}(esPhinx, esPhinx.ui));
<|endoftext|>


<commit_before>var nullCache = require('./nullCache.js').nullCache;

class memCache extends nullCache {
	constructor() {
		super();
		this.cache = {};
	}

	has(req) {
		return typeof this.cache[this._hash(req)] != 'undefined';
	}

	send(req, res) {
		if (this.has(req)) {
			var data = this.cache[this._hash(req)].content;
			res.setResponseCode(this.cache[this._hash(req)].response_code);
			res.setContentType(this.cache[this._hash(req)].mime_type);
			res.setLastModified(this.getLastModified(req));
			res.setContent(data);
			res.send();
		}
	}

	getLastModified(req) {
		if (this.has(req)) {
			return (this.cache[this._hash(req)].time).toUTCString();
		} else {
			return false;
		}
	}

	validate(req) {
		var cached = this.cache[this._hash(req)] || false;
		if (this.has(req) && (cachedDate = (cached.time).getTime())) {z
			for (var i = cached.dependencies.length - 1; i >= 0; i--) {
				try {
					if ((_fs.statSync(cached.dependencies[i]).mtime).getTime() > cachedDate) {
						return false;
					}
				} catch (e) {
					return false;
				}
			};
			return true;
		} else {
			return false;
		}
	}

	del(req) {
		if (this.has(req)) {
			console.log("Remove cache file: " + this._hash(req));
			this.cache[this._hash(req)] = undefined;
		}
	}

	clear() {
		this.cache = {};
	}

	add(req, cont, mime, code, dependsOn) {
		var data = {
			mime_type: mime,
			response_code: code,
			time: new Date(),
			dependencies: dependsOn,
			content: cont
		}
		console.log("Add mem cache " + this._hash(req));
		this.cache[this._hash(req)] = data;
	}

	_hash(req) {
		return super._hash(req);
	}

}

exports.memCache = memCache;
<commit_msg>remove obsolete function<commit_after>var nullCache = require('./nullCache.js').nullCache;

class memCache extends nullCache {
	constructor() {
		super();
		this.cache = {};
	}

	has(req) {
		return typeof this.cache[this._hash(req)] != 'undefined';
	}

	send(req, res) {
		if (this.has(req)) {
			var data = this.cache[this._hash(req)].content;
			res.setResponseCode(this.cache[this._hash(req)].response_code);
			res.setContentType(this.cache[this._hash(req)].mime_type);
			res.setLastModified(this.getLastModified(req));
			res.setContent(data);
			res.send();
		}
	}

	getLastModified(req) {
		if (this.has(req)) {
			return (this.cache[this._hash(req)].time).toUTCString();
		} else {
			return false;
		}
	}

	del(req) {
		if (this.has(req)) {
			console.log("Remove cache file: " + this._hash(req));
			this.cache[this._hash(req)] = undefined;
		}
	}

	clear() {
		this.cache = {};
	}

	add(req, cont, mime, code, dependsOn) {
		var data = {
			mime_type: mime,
			response_code: code,
			time: new Date(),
			dependencies: dependsOn,
			content: cont
		}
		console.log("Add mem cache " + this._hash(req));
		this.cache[this._hash(req)] = data;
	}

	_hash(req) {
		return super._hash(req);
	}

}

exports.memCache = memCache;
<|endoftext|>


<commit_before>import coreUtils from '@opentripplanner/core-utils'
import React from 'react'
import { Button } from 'react-bootstrap'
import { connect } from 'react-redux'
import styled, { css } from 'styled-components'

import * as uiActions from '../../actions/ui'
import Map from '../map/map'
import Icon from '../narrative/icon'
import NarrativeItineraries from '../narrative/narrative-itineraries'
import {
  getActiveItineraries,
  getActiveSearch,
  getResponsesWithErrors
} from '../../util/state'

import MobileContainer from './container'
import ResultsError from './results-error'
import ResultsHeader from './results-header'

const StyledMobileContainer = styled(MobileContainer)`
  .options > .header {
    margin: 10px;
  }

  &.otp.mobile .mobile-narrative-container {
    bottom: 0;
    left: 0;
    overflow-y: auto;
    padding: 0;
    position: fixed;
    right: 0;
  }
`

const ExpandMapButton = styled(Button)`
  bottom: 10px;
  left: 10px;
  position: absolute;
  z-index: 999999;
`

const NARRATIVE_SPLIT_TOP_PERCENT = 45

// Styles for the results map also include prop-independent styles copied from mobile.css.
const ResultsMap = styled.div`
  bottom: ${props => props.expanded ? '0' : `${100 - NARRATIVE_SPLIT_TOP_PERCENT}%`};
  display: ${props => props.visible ? 'inherit' : 'none'};
  left: 0;
  position: fixed;
  right: 0;
  top: 100px;
`

const narrativeCss = css`
  top: ${props => props.visible ? (props.expanded ? '100px' : `${NARRATIVE_SPLIT_TOP_PERCENT}%`) : '100%'};
  transition: top 300ms;
`

const StyledResultsError = styled(ResultsError)`
  display: ${props => props.visible ? 'inherit' : 'none'};
  ${narrativeCss}
`

const NarrativeContainer = styled.div`
  ${narrativeCss}
`

const { ItineraryView } = uiActions

/**
 * This component renders the mobile view of itinerary results from batch routing,
 * and features a split view between the map and itinerary results or narratives.
 */
const BatchMobileResultsScreen = ({
  errors,
  itineraries,
  itineraryView,
  toggleBatchResultsMap
}) => {
  const hasErrorsAndNoResult = itineraries.length === 0 && errors.length > 0
  const mapExpanded = itineraryView === ItineraryView.LEG_HIDDEN || itineraryView === ItineraryView.LIST_HIDDEN
  const itineraryExpanded = itineraryView === ItineraryView.FULL

  return (
    <StyledMobileContainer>
      <ResultsHeader />
      <ResultsMap
        expanded={mapExpanded}
        visible={!itineraryExpanded}
      >
        <Map />
        <ExpandMapButton
          bsSize='small'
          onClick={toggleBatchResultsMap}
        >
          <Icon name={mapExpanded ? 'list-ul' : 'arrows-alt'} />{' '}
          {mapExpanded ? 'Show results' : 'Expand map'}
        </ExpandMapButton>
      </ResultsMap>
      {hasErrorsAndNoResult
        ? <StyledResultsError
          error={errors[0]}
          expanded={itineraryExpanded}
          visible={!mapExpanded}
        />
        : (
          <NarrativeContainer
            className='mobile-narrative-container'
            expanded={itineraryExpanded}
            visible={!mapExpanded}
          >
            <NarrativeItineraries
              containerStyle={{
                background: '#fff',
                display: 'flex',
                flexDirection: 'column',
                height: '100%',
                width: '100%'
              }}
            />
          </NarrativeContainer>
        )
      }
    </StyledMobileContainer>
  )
}

// connect to the redux store

const mapStateToProps = (state, ownProps) => {
  const activeSearch = getActiveSearch(state.otp)
  const urlParams = coreUtils.query.getUrlParams()
  return {
    activeLeg: activeSearch ? activeSearch.activeLeg : null,
    errors: getResponsesWithErrors(state.otp),
    itineraries: getActiveItineraries(state.otp),
    itineraryView: urlParams.ui_itineraryView || AULT
  }
}

const mapDispatchToProps = {
  toggleBatchResultsMap: uiActions.toggleBatchResultsMap
}

export default connect(mapStateToProps, mapDispatchToProps)(BatchMobileResultsScreen)
<commit_msg>refactor(Fix typos):<commit_after>import coreUtils from '@opentripplanner/core-utils'
import React from 'react'
import { Button } from 'react-bootstrap'
import { connect } from 'react-redux'
import styled, { css } from 'styled-components'

import * as uiActions from '../../actions/ui'
import Map from '../map/map'
import Icon from '../narrative/icon'
import NarrativeItineraries from '../narrative/narrative-itineraries'
import {
  getActiveItineraries,
  getActiveSearch,
  getResponsesWithErrors
} from '../../util/state'

import MobileContainer from './container'
import ResultsError from './results-error'
import ResultsHeader from './results-header'

const StyledMobileContainer = styled(MobileContainer)`
  .options > .header {
    margin: 10px;
  }

  &.otp.mobile .mobile-narrative-container {
    bottom: 0;
    left: 0;
    overflow-y: auto;
    padding: 0;
    position: fixed;
    right: 0;
  }
`

const ExpandMapButton = styled(Button)`
  bottom: 10px;
  left: 10px;
  position: absolute;
  z-index: 999999;
`

const NARRATIVE_SPLIT_TOP_PERCENT = 45

// Styles for the results map also include prop-independent styles copied from mobile.css.
const ResultsMap = styled.div`
  bottom: ${props => props.expanded ? '0' : `${100 - NARRATIVE_SPLIT_TOP_PERCENT}%`};
  display: ${props => props.visible ? 'inherit' : 'none'};
  left: 0;
  position: fixed;
  right: 0;
  top: 100px;
`

const narrativeCss = css`
  top: ${props => props.visible ? (props.expanded ? '100px' : `${NARRATIVE_SPLIT_TOP_PERCENT}%`) : '100%'};
  transition: top 300ms;
`

const StyledResultsError = styled(ResultsError)`
  display: ${props => props.visible ? 'inherit' : 'none'};
  ${narrativeCss}
`

const NarrativeContainer = styled.div`
  ${narrativeCss}
`

const { ItineraryView } = uiActions

/**
 * This component renders the mobile view of itinerary results from batch routing,
 * and features a split view between the map and itinerary results or narratives.
 */
const BatchMobileResultsScreen = ({
  errors,
  itineraries,
  itineraryView,
  toggleBatchResultsMap
}) => {
  const hasErrorsAndNoResult = itineraries.length === 0 && errors.length > 0
  const mapExpanded = itineraryView === ItineraryView.LEG_HIDDEN || itineraryView === ItineraryView.LIST_HIDDEN
  const itineraryExpanded = itineraryView === ItineraryView.FULL

  return (
    <StyledMobileContainer>
      <ResultsHeader />
      <ResultsMap
        expanded={mapExpanded}
        visible={!itineraryExpanded}
      >
        <Map />
        <ExpandMapButton
          bsSize='small'
          onClick={toggleBatchResultsMap}
        >
          <Icon name={mapExpanded ? 'list-ul' : 'arrows-alt'} />{' '}
          {mapExpanded ? 'Show results' : 'Expand map'}
        </ExpandMapButton>
      </ResultsMap>
      {hasErrorsAndNoResult
        ? <StyledResultsError
          error={errors[0]}
          expanded={itineraryExpanded}
          visible={!mapExpanded}
        />
        : (
          <NarrativeContainer
            className='mobile-narrative-container'
            expanded={itineraryExpanded}
            visible={!mapExpanded}
          >
            <NarrativeItineraries
              containerStyle={{
                background: '#fff',
                display: 'flex',
                flexDirection: 'column',
                height: '100%',
                width: '100%'
              }}
            />
          </NarrativeContainer>
        )
      }
    </StyledMobileContainer>
  )
}

// connect to the redux store

const mapStateToProps = (state, ownProps) => {
  const activeSearch = getActiveSearch(state.otp)
  const urlParams = coreUtils.query.getUrlParams()
  return {
    activeLeg: activeSearch ? activeSearch.activeLeg : null,
    errors: getResponsesWithErrors(state.otp),
    itineraries: getActiveItineraries(state.otp),
    itineraryView: urlParams.ui_itineraryView || ItineraryView.LIST
  }
}

const mapDispatchToProps = {
  toggleBatchResultsMap: uiActions.toggleBatchResultsMap
}

export default connect(mapStateToProps, mapDispatchToProps)(BatchMobileResultsScreen)
<|endoftext|>


<commit_before>var _ = require("lodash");
var async = require("async");
var config = require("config");
var mongoose = require("mongoose");

/**
 * 连接数据库。
 * @param {Function(err)} [p_callback]
 */
exports.connect = function (p_callback)
{
    mongoose.connect(
        config.db,
        {
            server: {
                auto_reconnect: config.auto_reconnect,
                poolSize: config.poolSize
            },
        },
        function (err)
        {
            _connected = !err;
            _monitor();
            if (_.isFunction(p_callback))
            {
                p_callback(err);
            }
        }
    );
};

var _connected = false;
/**
 * 检查数据库是否已连接。
 */
 exports.connected = function ()
{
    return _connected;
};

/**
 * 删除所有集合。
 * @param {Function(err)} [p_callback]
 */
 exports.dropAllCollections = function (p_callback)
{
    async.each(mongoose.connection.collections, function (collection, done)
    {
        collection.drop(done);
    },
    function (err)
    {
        if (_.isFunction(p_callback))
        {
            if (!err || err.message == "ns not found")
            {
                p_callback()
            }
            else
            {
                p_callback(err);
            }
        }
    });
};

/**
 * 监控数据库状态。
 */
var _monitor = function ()
{
    var db = mongoose.connection.db;
    db.on("reconnect", function ()
    {
        _connected = true;
    });

    db.on("close", function ()
    {
        _connected = false;
    });

    db.on("error", function ()
    {
        _connected = false;
    });
};<commit_msg>add start database function<commit_after>var fs = require("fs");
var _ = require("lodash");
var path = require("path");
var async = require("async");
var config = require("config");
var cp = require("child_process");
var mongoose = require("mongoose");

/**
 * 启动数据库（Server）。
 * @param {Function(err)} [p_callback]
 */
exports.start = function (p_callback)
{
    var dbpath = path.resolve(__dirname, "../db");
    if (!fs.existsSync(dbpath))
    {
        fs.mkdirSync(dbpath);
    }

    if (fs.existsSync(dbpath))
    {
        cp.execFile("mongod", ["--dbpath", dbpath]);
        setTimeout(p_callback, 1000);
    }
    else
    {
        p_callback(new Error("Can not find/create database dir: " + dbpath));
    }
};

/**
 * 连接数据库。
 * @param {Function(err)} [p_callback]
 */
exports.connect = function (p_callback)
{
    mongoose.connect(
        config.db,
        {
            server: {
                auto_reconnect: config.auto_reconnect,
                poolSize: config.poolSize
            },
        },
        function (err)
        {
            _connected = !err;
            _monitor();
            if (_.isFunction(p_callback))
            {
                p_callback(err);
            }
        }
    );
};

var _connected = false;
/**
 * 检查数据库是否已连接。
 */
 exports.connected = function ()
{
    return _connected;
};

/**
 * 删除所有集合。
 * @param {Function(err)} [p_callback]
 */
 exports.dropAllCollections = function (p_callback)
{
    async.each(mongoose.connection.collections, function (collection, done)
    {
        collection.drop(done);
    },
    function (err)
    {
        if (_.isFunction(p_callback))
        {
            if (!err || err.message == "ns not found")
            {
                p_callback()
            }
            else
            {
                p_callback(err);
            }
        }
    });
};

/**
 * 监控数据库状态。
 */
var _monitor = function ()
{
    var db = mongoose.connection.db;
    db.on("reconnect", function ()
    {
        _connected = true;
    });

    db.on("close", function ()
    {
        _connected = false;
    });

    db.on("error", function ()
    {
        _connected = false;
    });
};<|endoftext|>


<commit_before>/* ex: set tabstop=2 softtabstop=2 shiftwidth=2 : */

var features = {
  // PLATFORM
  android:    !!navigator.userAgent.match(/Android/i),
  blackBerry: !!navigator.userAgent.match(/BlackBerry/i),
  iOS:        !!navigator.userAgent.match(/iP(hone|ad|od)/i),
  ieMobile:   !!navigator.userAgent.match(/IEMobile/i),
  // desktop
  ie:         !!document.all,
  firefox:    !document.layers && !document.all,
  opera:      !!window.opera,

  platform:   ( navigator.appVersion || navigator.userAgent ),
  isLocalFile:(location.protocol === "file:"),

  webapp: /webapp/.test( location.search ) || navigator.userAgent.indexOf("Mobile"),

  // FEATURES
  // is retina display, or more generally speaking,
  // What is the device's pixel ratio?
  retina:     ( window.devicePixelRatio || 1 ) - 1,
  // detecting touch capability
  // http://stackoverflow.com/questions/4817029/whats-the-best-way-to-detect-a-touch-screen-device-using-javascript
  touchInput: !!( 'ontouchstart' in window ), // cannot use window.ontouchstart
  // has web SQL
  webSQL:     !!window.openDatabase,
  // has indexDB
  indexDB:    !!window.IDBDatabase,
};

features = features || {};

features.mobile = features.android || features.ios || features.blackBerry || features.ieMobile || false;

// debug mode
features.debugLevel = features.isLocalFile ? 0 : ( document.cookie.match( /dbg/ ) || 0 );

features.version = (function(){
  var ua = navigator.userAgent;
  if ( features.ios ) {
    return parseFloat( ua.match( /iP(?:hone|ad|od);\ (?:U;\ )?CPU\ (?:(?:iPhone\ )?)OS\ ([0-9_]+)/ )[1].replace( /_/, "." ) );
  }
  if ( features.android ) {
    return parseFloat( ua.slice( ua.indexOf( "ndroid" ) + 7 ) );
  }
}());
// Is this falseage running in incognito/private mode?
features.incognito = (function() {
  if ( features.isLocalFile || !window.localStorage ) {
    return true;
  }
  try {
    // just pick a least likely name
    localStorage.setItem( "ಠ_ಠ", "ಠ_ಠ" );
    return false;
  }
  catch( e ) {
    return true;
  }
}());
<commit_msg>fixed error when running on about: page<commit_after>/* ex: set tabstop=2 softtabstop=2 shiftwidth=2 : */

var features = {
  // PLATFORM
  android:    !!navigator.userAgent.match(/Android/i),
  blackBerry: !!navigator.userAgent.match(/BlackBerry/i),
  iOS:        !!navigator.userAgent.match(/iP(hone|ad|od)/i),
  ieMobile:   !!navigator.userAgent.match(/IEMobile/i),
  // desktop
  ie:         !!document.all,
  firefox:    !document.layers && !document.all,
  opera:      !!window.opera,

  platform:   ( navigator.appVersion || navigator.userAgent ),
  isLocalFile:(location.protocol !== "http:" && location.protocol !== "https:"),

  webapp: /webapp/.test( location.search ) || navigator.userAgent.indexOf("Mobile"),

  // FEATURES
  // is retina display, or more generally speaking,
  // What is the device's pixel ratio?
  retina:     ( window.devicePixelRatio || 1 ) - 1,
  // detecting touch capability
  // http://stackoverflow.com/questions/4817029/whats-the-best-way-to-detect-a-touch-screen-device-using-javascript
  touchInput: !!( 'ontouchstart' in window ), // cannot use window.ontouchstart
  // has web SQL
  webSQL:     !!window.openDatabase,
  // has indexDB
  indexDB:    !!window.IDBDatabase
};

features = features || {};

features.mobile = features.android || features.ios || features.blackBerry || features.ieMobile || false;

// debug mode
features.debugLevel = features.isLocalFile ? 0 : ( document.cookie.match( /dbg/ ) || 0 );

features.version = (function(){
  var ua = navigator.userAgent;
  if ( features.ios ) {
    return parseFloat( ua.match( /iP(?:hone|ad|od);\ (?:U;\ )?CPU\ (?:(?:iPhone\ )?)OS\ ([0-9_]+)/ )[1].replace( /_/, "." ) );
  }
  if ( features.android ) {
    return parseFloat( ua.slice( ua.indexOf( "ndroid" ) + 7 ) );
  }
}());
// Is this falseage running in incognito/private mode?
features.incognito = (function() {
  if ( features.isLocalFile || !window.localStorage ) {
    return true;
  }
  try {
    // just pick a least likely name
    localStorage.setItem( "ಠ_ಠ", "ಠ_ಠ" );
    return false;
  }
  catch( e ) {
    return true;
  }
}());
<|endoftext|>


<commit_before>export default function() {
  return `
vec4 pack (float depth)
{
  const vec4 bitSh = vec4(256 * 256 * 256,
                          256 * 256,
                          256,
                          1.0);
  const vec4 bitMsk = vec4(0,
                           1.0 / 256.0,
                           1.0 / 256.0,
                           1.0 / 256.0);
  vec4 comp = fract(depth * bitSh);
  comp -= comp.xxyz * bitMsk;
  return comp;
}

float unpack (vec4 colour)
{
  const vec4 bitShifts = vec4(1.0 / (256.0 * 256.0 * 256.0),
                              1.0 / (256.0 * 256.0),
                              1.0 / 256.0,
                              1);
  return dot(colour , bitShifts);
}

vec4 bumpFromDepth(sampler2D texture, vec2 uv, float scale) {
  vec2 size = vec2(.002, .0) * scale;
  vec3 off = vec3(-.001, 0., .001) * scale;

  float s11 = unpack(texture2D(texture, uv));
  float s01 = unpack(texture2D(texture, uv + off.xy));
  float s21 = unpack(texture2D(texture, uv + off.zy));
  float s10 = unpack(texture2D(texture, uv + off.yx));
  float s12 = unpack(texture2D(texture, uv + off.yz));
  vec3 va = normalize(vec3(size.xy, s21 - s01));
  vec3 vb = normalize(vec3(size.yx, s12 - s10));
  vec4 bump = vec4(cross(va,vb), s11);
  bump.xyz = bump.xyz * .5 + .5;
  return bump;
}
`};
<commit_msg>remove RGB normalization in depth-glsl<commit_after>export default function() {
  return `
vec4 pack (float depth)
{
  const vec4 bitSh = vec4(256 * 256 * 256,
                          256 * 256,
                          256,
                          1.0);
  const vec4 bitMsk = vec4(0,
                           1.0 / 256.0,
                           1.0 / 256.0,
                           1.0 / 256.0);
  vec4 comp = fract(depth * bitSh);
  comp -= comp.xxyz * bitMsk;
  return comp;
}

float unpack (vec4 colour)
{
  const vec4 bitShifts = vec4(1.0 / (256.0 * 256.0 * 256.0),
                              1.0 / (256.0 * 256.0),
                              1.0 / 256.0,
                              1);
  return dot(colour , bitShifts);
}

vec4 bumpFromDepth(sampler2D texture, vec2 uv, float scale) {
  vec2 size = vec2(.002, .0) * scale;
  vec3 off = vec3(-.001, 0., .001) * scale;

  float s11 = unpack(texture2D(texture, uv));
  float s01 = unpack(texture2D(texture, uv + off.xy));
  float s21 = unpack(texture2D(texture, uv + off.zy));
  float s10 = unpack(texture2D(texture, uv + off.yx));
  float s12 = unpack(texture2D(texture, uv + off.yz));
  vec3 va = normalize(vec3(size.xy, s21 - s01));
  vec3 vb = normalize(vec3(size.yx, s12 - s10));
  vec4 bump = vec4(cross(va,vb), s11);
  return bump;
}
`};
<|endoftext|>