<commit_before>'use strict';
var fs = require('fs');
var JSONStream = require('JSONStream');
var eventStream = require('event-stream');
var os = require('os');
var path = require('path');
var sha1 = require('sha1');
var _ = require('underscore');
var folder = os.tmpdir();
//These are the most usual ids which come in geojson files.
var ids = ['id', '_id', '_fromWay', '_toWay'];
var avoidDuplicates = [];
module.exports = {
  formatGeojson,
  formatFeature
};

function handleData(data, file) {
  data = formatFeature(data);
  if (avoidDuplicates.indexOf(data.properties._key) < 0) {
    avoidDuplicates.push(data.properties._key);
    var row = `${JSON.stringify(data)}\n`;
    fs.appendFileSync(file, row, function(err) {
      if (err) console.log(err);
    });
  }
}
/**
 * Stream a GeoJSON file to count the number of rows
 * @param {string} geojsonFile path to a local GeoJSON file
 * @param {object} task metadata
 * @param {function} cb success callback passing updated task as parameter
 * @returns {object} task with `items` property
 */
function formatGeojson(geojsonFile, task, cb) {
  var numRows = 0;
  var file = path.join(folder, task.idtask);
  fs.writeFileSync(file, '');
  var fileStream = fs.createReadStream(geojsonFile, {
    encoding: 'utf8'
  });
  fileStream.pipe(JSONStream.parse('features.*'))
    .pipe(eventStream.mapSync(function(data) {
      handleData(data, file);
      return data
    })).on('error', function(err) {
      console.log(err)
    }).on('close', function() {
      task.value.stats[task.value.stats.length - 1].date = task.value.updated;
      task.value.stats[task.value.stats.length - 1].items = avoidDuplicates.length;
      cb(task);
    });
}

/**
 * Format the data
 * - add _key, hash of the feature
 * - add _time, current time
 * - add _osmId , which is the id of osm object
 * - add _osmType, which is the type of osm object
 * @param {object} a feature of geojson
 * @returns {object} a feature which will be a item in ES
 */
function formatFeature(data) {
  var hash = sha1(JSON.stringify(data));
  var time = Math.round((new Date()).getTime() / 1000);
  data.properties._key = hash;
  data.properties._time = time;
  if (data.properties.relations) {
    data.properties._osmType = 'relation';
  } else if (data.geometry.type === 'MultiPoint' || data.geometry.type === 'LineString' || data.geometry.type === 'MultiLineString' || data.geometry.type === 'Polygon' || data.geometry.type === 'MultiPolygon') {
    data.properties._osmType = 'way';
  } else if (data.geometry.type === 'Point') {
    data.properties._osmType = 'node';
  }
  data = replaceSC(data);
  for (var i = 0; i < ids.length; i++) {
    var id = ids[i];
    if (data.properties[id]) {
      data.properties._osmId = data.properties[id];
      //format overpass geojson files
      var typeId = data.properties._osmId.toString().split('\_');
      if (typeId.length === 2) {
        data.properties._osmId = typeId[1];
        data.properties._osmType = typeId[0];
      }
    }
  }
  return data;
}

function replaceSC(obj) {
  if (_.isArray(obj)) {
    for (var k = 0; k < obj.length; k++) {
      obj[k] = replaceSC(obj[k]);
    }
  } else {
    var keys = _.keys(obj);
    for (var i = 0; i < keys.length; i++) {
      var key = keys[i].replace(/[^A-Za-z]/g, '_');
      if (key !== keys[i]) {
        obj[key] = obj[keys[i]];
        delete obj[keys[i]];
      }
      /*eslint valid-typeof: "error"*/
      if (_.isObject(obj[key]) && key !== 'geometry') {
        obj[key] = replaceSC(obj[key]);
      } else if (typeof obj[key] === 'string' || obj[key] instanceof String) {
        obj[key] = obj[key].replace(/[^a-zA-Z0-9]/g, '_');
      }
    }
  }
  return obj;
}
<commit_msg>fix appendfile<commit_after>'use strict';
var fs = require('fs');
var JSONStream = require('JSONStream');
var eventStream = require('event-stream');
var os = require('os');
var path = require('path');
var sha1 = require('sha1');
var _ = require('underscore');
var folder = os.tmpdir();
//These are the most usual ids which come in geojson files.
var ids = ['id', '_id', '_fromWay', '_toWay'];
var avoidDuplicates = [];
module.exports = {
  formatGeojson,
  formatFeature
};

function handleData(data, file) {
  data = formatFeature(data);
  if (avoidDuplicates.indexOf(data.properties._key) < 0) {
    avoidDuplicates.push(data.properties._key);
    var row = `${JSON.stringify(data)}\n`;
    fs.appendFile(file, row, function(err) {
      if (err) console.log(err);
    });
  }
}
/**
 * Stream a GeoJSON file to count the number of rows
 * @param {string} geojsonFile path to a local GeoJSON file
 * @param {object} task metadata
 * @param {function} cb success callback passing updated task as parameter
 * @returns {object} task with `items` property
 */
function formatGeojson(geojsonFile, task, cb) {
  var numRows = 0;
  var file = path.join(folder, task.idtask);
  fs.writeFileSync(file, '');
  var fileStream = fs.createReadStream(geojsonFile, {
    encoding: 'utf8'
  });
  fileStream.pipe(JSONStream.parse('features.*'))
    .pipe(eventStream.mapSync(function(data) {
      handleData(data, file);
      return data
    })).on('error', function(err) {
      console.log(err)
    }).on('close', function() {
      task.value.stats[task.value.stats.length - 1].date = task.value.updated;
      task.value.stats[task.value.stats.length - 1].items = avoidDuplicates.length;
      cb(task);
    });
}

/**
 * Format the data
 * - add _key, hash of the feature
 * - add _time, current time
 * - add _osmId , which is the id of osm object
 * - add _osmType, which is the type of osm object
 * @param {object} a feature of geojson
 * @returns {object} a feature which will be a item in ES
 */
function formatFeature(data) {
  var hash = sha1(JSON.stringify(data));
  var time = Math.round((new Date()).getTime() / 1000);
  data.properties._key = hash;
  data.properties._time = time;
  if (data.properties.relations) {
    data.properties._osmType = 'relation';
  } else if (data.geometry.type === 'MultiPoint' || data.geometry.type === 'LineString' || data.geometry.type === 'MultiLineString' || data.geometry.type === 'Polygon' || data.geometry.type === 'MultiPolygon') {
    data.properties._osmType = 'way';
  } else if (data.geometry.type === 'Point') {
    data.properties._osmType = 'node';
  }
  data = replaceSC(data);
  for (var i = 0; i < ids.length; i++) {
    var id = ids[i];
    if (data.properties[id]) {
      data.properties._osmId = data.properties[id];
      //format overpass geojson files
      var typeId = data.properties._osmId.toString().split('\_');
      if (typeId.length === 2) {
        data.properties._osmId = typeId[1];
        data.properties._osmType = typeId[0];
      }
    }
  }
  return data;
}

function replaceSC(obj) {
  if (_.isArray(obj)) {
    for (var k = 0; k < obj.length; k++) {
      obj[k] = replaceSC(obj[k]);
    }
  } else {
    var keys = _.keys(obj);
    for (var i = 0; i < keys.length; i++) {
      var key = keys[i].replace(/[^A-Za-z]/g, '_');
      if (key !== keys[i]) {
        obj[key] = obj[keys[i]];
        delete obj[keys[i]];
      }
      /*eslint valid-typeof: "error"*/
      if (_.isObject(obj[key]) && key !== 'geometry') {
        obj[key] = replaceSC(obj[key]);
      } else if (typeof obj[key] === 'string' || obj[key] instanceof String) {
        obj[key] = obj[key].replace(/[^a-zA-Z0-9]/g, '_');
      }
    }
  }
  return obj;
}<|endoftext|>


<commit_before>'use strict'

var expect = require('chai').expect;
var lgLogic = require('../lib/_lg-logic.js');
var postcss = require('postcss');

describe('calcValue works as it should', () => {
  it('gutter, rounder, and unit ✅', () => {
    var testCase = lgLogic.calcValue('1/3', '30px', 100, 'vw');

    var expectedResult = `calc(100vw * 1/3 - (30px - 30px * 1/3))`;

    expect(testCase).to.equal(expectedResult);
  });
  it('no gutter ✅', () => {
    var testCase = lgLogic.calcValue('1/3', '0', 99.9);

    var expectedResult = `calc(99.9% * 1/3)`;

    expect(testCase).to.equal(expectedResult);
  });
  it('no gutter ✅  when gutter is undefined', () => {
    var testCase = lgLogic.calcValue('1/3', undefined, 99.9);

    var expectedResult = `calc(99.9% * 1/3)`;

    expect(testCase).to.equal(expectedResult);
  });
});

describe('Units are validated based on if they make sense', () => {
  it('only allows what is in the array of accepted units', () => {
    expect(lgLogic.validateUnit('vw', ['%','vw'])).to.be.true;
    expect(lgLogic.validateUnit('%', ['%','vw'])).to.be.true;
    expect(lgLogic.validateUnit('px', ['%','vw', 'px', 'em'])).to.be.true;
    expect(lgLogic.validateUnit('foobar', ['%','vw'])).to.not.be.true;
    expect(lgLogic.validateUnit(3, ['%','vw'])).to.not.be.true;
  });
});

describe('parseLostProperty works as it should', () => {
  it('returns default value if property not found', () => {
    var css = 'a { lost-unit: vw; lost-center-padding: 25px }';
    var nodes = postcss.parse(css).nodes[0].nodes;

    var testCase = lgLogic.parseLostProperty(nodes, 'lost-column-rounder', 0);
    var expectedResult = 0;

    expect(testCase).to.equal(expectedResult);
  });

  it('returns value if property is found', () => {
    var css = 'a { lost-unit: vw; lost-center-padding: 25px }';
    var nodes = postcss.parse(css).nodes[0].nodes;

    var testCase = lgLogic.parseLostProperty(nodes, 'lost-unit', '%');
    var expectedResult = 'vw';

    expect(testCase).to.equal(expectedResult);
  });

  it('property node removed if found', () => {
    var css = 'a { height: 100px; lost-unit: vw; lost-center-padding: 25px }';
    var nodes = postcss.parse(css).nodes[0].nodes;

    lgLogic.parseLostProperty(nodes, 'lost-unit', '%');

    var testCase = nodes.length;
    var expectedResult = 2;

    expect(testCase).to.equal(expectedResult);
  });

});
<commit_msg>Updates parseLostProperty unit test.<commit_after>'use strict'

var expect = require('chai').expect;
var lgLogic = require('../lib/_lg-logic.js');
var postcss = require('postcss');

describe('calcValue works as it should', () => {
  it('gutter, rounder, and unit ✅', () => {
    var testCase = lgLogic.calcValue('1/3', '30px', 100, 'vw');

    var expectedResult = `calc(100vw * 1/3 - (30px - 30px * 1/3))`;

    expect(testCase).to.equal(expectedResult);
  });
  it('no gutter ✅', () => {
    var testCase = lgLogic.calcValue('1/3', '0', 99.9);

    var expectedResult = `calc(99.9% * 1/3)`;

    expect(testCase).to.equal(expectedResult);
  });
  it('no gutter ✅  when gutter is undefined', () => {
    var testCase = lgLogic.calcValue('1/3', undefined, 99.9);

    var expectedResult = `calc(99.9% * 1/3)`;

    expect(testCase).to.equal(expectedResult);
  });
});

describe('Units are validated based on if they make sense', () => {
  it('only allows what is in the array of accepted units', () => {
    expect(lgLogic.validateUnit('vw', ['%','vw'])).to.be.true;
    expect(lgLogic.validateUnit('%', ['%','vw'])).to.be.true;
    expect(lgLogic.validateUnit('px', ['%','vw', 'px', 'em'])).to.be.true;
    expect(lgLogic.validateUnit('foobar', ['%','vw'])).to.not.be.true;
    expect(lgLogic.validateUnit(3, ['%','vw'])).to.not.be.true;
  });
});

describe('parseLostProperty works as it should', () => {
  it('returns default value if property not found', () => {
    var css = 'a { lost-unit: vw; lost-center-padding: 25px }';
    var nodes = postcss.parse(css).nodes[0].nodes;

    var testCase = lgLogic.parseLostProperty(nodes, 'lost-column-rounder', 0);
    var expectedResult = 0;

    expect(testCase).to.equal(expectedResult);
  });

  it('returns value if property is found', () => {
    var css = 'a { lost-unit: vw; lost-center-padding: 25px }';
    var nodes = postcss.parse(css).nodes[0].nodes;

    var testCase = lgLogic.parseLostProperty(nodes, 'lost-unit', '%');
    var expectedResult = 'vw';

    expect(testCase).to.equal(expectedResult);
  });

  it('property node removed if found', () => {
    var css = 'a { height: 100px; lost-unit: vw; lost-center-padding: 25px }';
    var cssProperties = postcss.parse(css);

    lgLogic.parseLostProperty(cssProperties.nodes[0].nodes, 'lost-unit', '%');

    var testCase = 'a { height: 100px; lost-center-padding: 25px }';
    var expectedResult = cssProperties.toString();

    expect(testCase).to.equal(expectedResult);
  });

});
<|endoftext|>


<commit_before>'use strict';

var Xmpp   = require('../../index').Xmpp
  , should = require('should')
  , events = require('events')
  , ltx    = require('ltx')

/* jshint -W030 */
describe('FTW', function() {

    var ftw, socket

    before(function() {
        socket = new events.EventEmitter()
        ftw = new Xmpp(socket)
    })

    describe('Returns JID parts', function() {

        beforeEach(function() {
            ftw.fullJid = {
                user: 'marty',
                domain: 'mcfly',
                resource: 'thefuture'
            }
        })

        it('Returns full JID', function() {
            ftw.getJidType('full').should.equal(
                ftw.fullJid.user + '@' +
                ftw.fullJid.domain + '/' +
                ftw.fullJid.resource
            )
        })

        it('Returns bare JID', function() {
            ftw.getJidType('bare').should.equal(
                ftw.fullJid.user + '@' +
                ftw.fullJid.domain
            )
        })

        it('Returns domain', function() {
            ftw.getJidType('domain').should.equal(
                ftw.fullJid.domain
            )
        })

        it('Returns undefined for unknown JID part type', function() {
            should.not.exist(ftw.getJidType('all'))
        })

    })

    describe('Tracking IDs', function() {

        it('Should error if no ID provided', function(done) {
            try {
                ftw.trackId()
                done('Expected exception')
            } catch (e) {
                e.message.should.equal(ftw.MISSING_STANZA_ID)
                done()
            }
        })

        it('Should accept an ID and capture', function(done) {
            var stanza = ltx.parse('<iq id="1" />')
            ftw.trackId('1', function(payload) {
                payload.should.eql(stanza)
                done()
            })
            ftw.catchTracked(stanza).should.be.true
        })

        it('Should return false if untracked ID', function() {
            var stanza = ltx.parse('<iq id="2" />')
            ftw.trackId('1', function() {})
            ftw.catchTracked(stanza).should.be.false
        })

        it('Should return false if no ID attribute', function() {
            var stanza = ltx.parse('<iq />')
            ftw.trackId('1', function() {})
            ftw.catchTracked(stanza).should.be.false
        })

        it('Should error if no callback provided', function(done) {
            try {
                ftw.trackId('1')
                done('Expected exception')
            } catch (e) {
                e.message.should.equal(ftw.MISSING_CALLBACK)
                done()
            }
        })

        it('Should error if non-function callback provided', function(done) {
            try {
                ftw.trackId('3', true)
                done('Expected exception')
            } catch (e) {
                e.message.should.equal(ftw.INVALID_CALLBACK)
                done()
            }
        })

        it('Should accept a stanza and capture', function(done) {
            var incomingStanza = ltx.parse('<iq id="4" />')
            var outGoingStanza = incomingStanza
            ftw.trackId(outGoingStanza, function(payload) {
                payload.should.eql(incomingStanza)
                done()
            })
            ftw.catchTracked(incomingStanza).should.be.true
        })

        it('Errors if stanza has no ID attribute', function(done) {
            try {
                var outgoingStanza = ltx.parse('<iq />')
                ftw.trackId(outgoingStanza, function() {})
                done('Expected exception')
            } catch (e) {
                e.message.should.equal(ftw.MISSING_STANZA_ID)
                done()
            }
        })

    })

    describe.only('Stanza ID spoofing protection', function() {

        it.skip('Should track a stanza from the same full JID', function(done) {

        })

        it.skip('Shouldn\'t track a stanza from a different JID', function(done) {

        })

        it.skip('Shouldn\'t track a stanza from the bare JID', function(done) {

        })

        it.skip('Assumes \'to\' address is server when not provided', function(done) {

        })

    })

})
<commit_msg>Pass initial JID tracking test<commit_after>'use strict';

var Xmpp   = require('../../index').Xmpp
  , should = require('should')
  , events = require('events')
  , ltx    = require('ltx')

/* jshint -W030 */
describe('FTW', function() {

    var ftw, socket

    before(function() {
        socket = new events.EventEmitter()
        ftw = new Xmpp(socket)
    })

    describe('Returns JID parts', function() {

        beforeEach(function() {
            ftw.fullJid = {
                user: 'marty',
                domain: 'mcfly',
                resource: 'thefuture'
            }
        })

        it('Returns full JID', function() {
            ftw.getJidType('full').should.equal(
                ftw.fullJid.user + '@' +
                ftw.fullJid.domain + '/' +
                ftw.fullJid.resource
            )
        })

        it('Returns bare JID', function() {
            ftw.getJidType('bare').should.equal(
                ftw.fullJid.user + '@' +
                ftw.fullJid.domain
            )
        })

        it('Returns domain', function() {
            ftw.getJidType('domain').should.equal(
                ftw.fullJid.domain
            )
        })

        it('Returns undefined for unknown JID part type', function() {
            should.not.exist(ftw.getJidType('all'))
        })

    })

    describe('Tracking IDs', function() {

        it('Should error if no ID provided', function(done) {
            try {
                ftw.trackId()
                done('Expected exception')
            } catch (e) {
                e.message.should.equal(ftw.MISSING_STANZA_ID)
                done()
            }
        })

        it('Should accept an ID and capture', function(done) {
            var stanza = ltx.parse('<iq id="1" />')
            ftw.trackId('1', function(payload) {
                payload.should.eql(stanza)
                done()
            })
            ftw.catchTracked(stanza).should.be.true
        })

        it('Should return false if untracked ID', function() {
            var stanza = ltx.parse('<iq id="2" />')
            ftw.trackId('1', function() {})
            ftw.catchTracked(stanza).should.be.false
        })

        it('Should return false if no ID attribute', function() {
            var stanza = ltx.parse('<iq />')
            ftw.trackId('1', function() {})
            ftw.catchTracked(stanza).should.be.false
        })

        it('Should error if no callback provided', function(done) {
            try {
                ftw.trackId('1')
                done('Expected exception')
            } catch (e) {
                e.message.should.equal(ftw.MISSING_CALLBACK)
                done()
            }
        })

        it('Should error if non-function callback provided', function(done) {
            try {
                ftw.trackId('3', true)
                done('Expected exception')
            } catch (e) {
                e.message.should.equal(ftw.INVALID_CALLBACK)
                done()
            }
        })

        it('Should accept a stanza and capture', function(done) {
            var incomingStanza = ltx.parse('<iq id="4" />')
            var outGoingStanza = incomingStanza
            ftw.trackId(outGoingStanza, function(payload) {
                payload.should.eql(incomingStanza)
                done()
            })
            ftw.catchTracked(incomingStanza).should.be.true
        })

        it('Errors if stanza has no ID attribute', function(done) {
            try {
                var outgoingStanza = ltx.parse('<iq />')
                ftw.trackId(outgoingStanza, function() {})
                done('Expected exception')
            } catch (e) {
                e.message.should.equal(ftw.MISSING_STANZA_ID)
                done()
            }
        })

    })

    describe.only('Stanza ID spoofing protection', function() {

        it('Should track a stanza from the same full JID', function(done) {
            var jid = 'you@example.com/resource'
            var id = '10'
            var outgoingStanza = ltx.parse(
                '<iq to="' + jid + '" id="' + id + '" />'
            )
            ftw.trackId(outgoingStanza, function(stanza) {
                stanza.attr('id').should.equal(id)
                stanza.attr('from').should.equal(jid)
                done()
            })
            var incomingStanza = outgoingStanza.clone()
            incomingStanza.attrs.from = incomingStanza.attrs.to
            delete incomingStanza.attrs.to
            ftw.catchTracked(incomingStanza)
        })

        it.skip('Shouldn\'t track a stanza from a different JID', function(done) {

        })

        it.skip('Shouldn\'t track a stanza from the bare JID', function(done) {

        })

        it.skip('Assumes \'to\' address is server when not provided', function(done) {

        })

    })

})
<|endoftext|>


<commit_before>import assert from 'power-assert';
import Luv    from '../src/luv';

describe('Luv', () => {

  describe('.constructor(l, u, v)', () => {

    it('should create an instance', () => {
      let luv = new Luv(42.782, 102.260, -3.495);
      assert(luv !== null);
      assert(luv instanceof Luv);
      assert.deepEqual(luv.values(), [42.782, 102.260, -3.495]);
    });

  });

  describe('.prototype.clone()', () => {

    it('should create a new instance', () => {
      let source = new Luv(42.782, 102.260, -3.495);
      let cloned = source.clone();
      assert(cloned !== null);
      assert(cloned !== source);
      assert(cloned instanceof Luv);
      assert.deepEqual(cloned.values(), source.values());
    });

  });

  describe('.prototype.luv()', () => {

    it('should return self', () => {
      let luv = new Luv(42.782, 102.260, -3.495);
      assert(luv.luv() === luv);
    });

  });

});
<commit_msg>Added a test case for Luv.prototype.xyz()<commit_after>import assert from 'power-assert';
import Luv    from '../src/luv';
import Xyz    from '../src/xyz';

describe('Luv', () => {

  describe('.constructor(l, u, v)', () => {

    it('should create an instance', () => {
      let luv = new Luv(42.782, 102.260, -3.495);
      assert(luv !== null);
      assert(luv instanceof Luv);
      assert.deepEqual(luv.values(), [42.782, 102.260, -3.495]);
    });

  });

  describe('.prototype.clone()', () => {

    it('should create a new instance', () => {
      let source = new Luv(42.782, 102.260, -3.495);
      let cloned = source.clone();
      assert(cloned !== null);
      assert(cloned !== source);
      assert(cloned instanceof Luv);
      assert.deepEqual(cloned.values(), source.values());
    });

  });

  describe('.prototype.luv()', () => {

    it('should return self', () => {
      let luv = new Luv(42.782, 102.260, -3.495);
      assert(luv.luv() === luv);
    });

  });

  describe('.prototype.xyz()', () => {

    it('should convert color space from Luv to XYZ', () => {
      let luv = new Luv(42.782, 102.260, -3.495);
      let xyz = luv.xyz();
      assert(xyz !== null);
      assert(xyz instanceof Xyz);
    });

  });

});
<|endoftext|>


<commit_before>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

//@ts-check

(function () {

	/**
	 * @returns {{mark(name:string):void, getMarks():{name:string, startTime:number}[]}}
	 */
	function _definePolyfillMarks(timeOrigin) {

		const _data = [];
		if (typeof timeOrigin === 'number') {
			_data.push('code/timeOrigin', timeOrigin);
		}

		function mark(name) {
			_data.push(name, Date.now());
		}
		function getMarks() {
			const result = [];
			for (let i = 0; i < _data.length; i += 2) {
				result.push({
					name: _data[i],
					startTime: _data[i + 1],
				});
			}
			return result;
		}
		return { mark, getMarks };
	}

	/**
	 * @returns {{mark(name:string):void, getMarks():{name:string, startTime:number}[]}}
	 */
	function _define() {

		if (typeof performance === 'object' && typeof performance.mark === 'function') {
			// in a browser context, reuse performance-util

			if (typeof performance.timeOrigin !== 'number' && !performance.timing) {
				// safari & webworker: because there is no timeOrigin and no workaround
				// we use the `Date.now`-based polyfill.
				return _definePolyfillMarks();

			} else {
				// use "native" performance for mark and getMarks
				return {
					mark(name) {
						performance.mark(name);
					},
					getMarks() {
						let timeOrigin = performance.timeOrigin;
						if (typeof timeOrigin !== 'number') {
							// safari: there is no timerOrigin but in renderers there is the timing-property
							// see https://bugs.webkit.org/show_bug.cgi?id=174862
							timeOrigin = performance.timing.navigationStart || performance.timing.redirectStart || performance.timing.fetchStart;
						}
						const result = [{ name: 'code/timeOrigin', startTime: Math.round(timeOrigin) }];
						for (const entry of performance.getEntriesByType('mark')) {
							result.push({
								name: entry.name,
								startTime: Math.round(timeOrigin + entry.startTime)
							});
						}
						return result;
					}
				};
			}

		} else if (typeof process === 'object') {
			// node.js: use the normal polyfill but add the timeOrigin
			// from the node perf_hooks API as very first mark
			const timeOrigin = Math.round((require.nodeRequire || require)('perf_hooks').performance.timeOrigin);
			return _definePolyfillMarks(timeOrigin);

		} else {
			// unknown environment
			console.trace('perf-util loaded in UNKNOWN environment');
			return _definePolyfillMarks();
		}
	}

	function _factory(sharedObj) {
		if (!sharedObj.MonacoPerformanceMarks) {
			sharedObj.MonacoPerformanceMarks = _define();
		}
		return sharedObj.MonacoPerformanceMarks;
	}

	// This module can be loaded in an amd and commonjs-context.
	// Because we want both instances to use the same perf-data
	// we store them globally

	// eslint-disable-next-line no-var
	var sharedObj;
	if (typeof global === 'object') {
		// nodejs
		sharedObj = global;
	} else if (typeof self === 'object') {
		// browser
		sharedObj = self;
	} else {
		sharedObj = {};
	}

	if (typeof define === 'function') {
		// amd
		define([], function () { return _factory(sharedObj); });
	} else if (typeof module === 'object' && typeof module.exports === 'object') {
		// commonjs
		module.exports = _factory(sharedObj);
	} else {
		console.trace('perf-util defined in UNKNOWN context (neither requirejs or commonjs)');
		sharedObj.perf = _factory(sharedObj);
	}

})();
<commit_msg>chore: fix perf hook integration with node environment<commit_after>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

//@ts-check

(function () {

	/**
	 * @returns {{mark(name:string):void, getMarks():{name:string, startTime:number}[]}}
	 */
	function _definePolyfillMarks(timeOrigin) {

		const _data = [];
		if (typeof timeOrigin === 'number') {
			_data.push('code/timeOrigin', timeOrigin);
		}

		function mark(name) {
			_data.push(name, Date.now());
		}
		function getMarks() {
			const result = [];
			for (let i = 0; i < _data.length; i += 2) {
				result.push({
					name: _data[i],
					startTime: _data[i + 1],
				});
			}
			return result;
		}
		return { mark, getMarks };
	}

	/**
	 * @returns {{mark(name:string):void, getMarks():{name:string, startTime:number}[]}}
	 */
	function _define() {

		// Identify browser environment when following property is not present
		// https://nodejs.org/dist/latest-v16.x/docs/api/perf_hooks.html#performancenodetiming
		if (typeof performance === 'object' && typeof performance.mark === 'function' && !performance.nodeTiming) {
			// in a browser context, reuse performance-util

			if (typeof performance.timeOrigin !== 'number' && !performance.timing) {
				// safari & webworker: because there is no timeOrigin and no workaround
				// we use the `Date.now`-based polyfill.
				return _definePolyfillMarks();

			} else {
				// use "native" performance for mark and getMarks
				return {
					mark(name) {
						performance.mark(name);
					},
					getMarks() {
						let timeOrigin = performance.timeOrigin;
						if (typeof timeOrigin !== 'number') {
							// safari: there is no timerOrigin but in renderers there is the timing-property
							// see https://bugs.webkit.org/show_bug.cgi?id=174862
							timeOrigin = performance.timing.navigationStart || performance.timing.redirectStart || performance.timing.fetchStart;
						}
						const result = [{ name: 'code/timeOrigin', startTime: Math.round(timeOrigin) }];
						for (const entry of performance.getEntriesByType('mark')) {
							result.push({
								name: entry.name,
								startTime: Math.round(timeOrigin + entry.startTime)
							});
						}
						return result;
					}
				};
			}

		} else if (typeof process === 'object') {
			// node.js: use the normal polyfill but add the timeOrigin
			// from the node perf_hooks API as very first mark
			const timeOrigin = Math.round((require.nodeRequire || require)('perf_hooks').performance.timeOrigin);
			return _definePolyfillMarks(timeOrigin);

		} else {
			// unknown environment
			console.trace('perf-util loaded in UNKNOWN environment');
			return _definePolyfillMarks();
		}
	}

	function _factory(sharedObj) {
		if (!sharedObj.MonacoPerformanceMarks) {
			sharedObj.MonacoPerformanceMarks = _define();
		}
		return sharedObj.MonacoPerformanceMarks;
	}

	// This module can be loaded in an amd and commonjs-context.
	// Because we want both instances to use the same perf-data
	// we store them globally

	// eslint-disable-next-line no-var
	var sharedObj;
	if (typeof global === 'object') {
		// nodejs
		sharedObj = global;
	} else if (typeof self === 'object') {
		// browser
		sharedObj = self;
	} else {
		sharedObj = {};
	}

	if (typeof define === 'function') {
		// amd
		define([], function () { return _factory(sharedObj); });
	} else if (typeof module === 'object' && typeof module.exports === 'object') {
		// commonjs
		module.exports = _factory(sharedObj);
	} else {
		console.trace('perf-util defined in UNKNOWN context (neither requirejs or commonjs)');
		sharedObj.perf = _factory(sharedObj);
	}

})();
<|endoftext|>


<commit_before>'use strict';

var expect = require('expect.js'),
	Migrator = require('../lib/migrator'),
	Path = require('path');

describe('migrator', function() {
	var migrator = new Migrator();

	it('connect', function(done) {
		migrator.connect(done);
	});

	describe('adapter', function() {
		var tryLoad,
			mockAdapter = function() {
				this.getTemplatePath = function() {};
			};

		before(function() {
			tryLoad = Migrator.prototype._tryLoadAdapter;
		});

		it('expect be loaded migrator-related first and than CWD-related', function(done) {
			var paths = [];
			Migrator.prototype._tryLoadAdapter = function(path) {
				paths.push(path);
				return paths.length === 2 ? mockAdapter : new Error('Whatever.');
			};

			new Migrator({
				adapter: 'X'
			});

			expect(paths[0]).eql('X');
			expect(paths[1].substr(-2, 2)).eql('/X');
			done();
		});

		it('expect to throw when both paths can not be resolved', function(done) {
			Migrator.prototype._tryLoadAdapter = function() {
				return new Error('Whatever.');
			};

			expect(function() {
				new Migrator({
					adapter: 'X'
				});
			}).to.throwError(/Whatever./);
			done();
		});

		after(function() {
			Migrator.prototype._tryLoadAdapter = tryLoad;
		});
	});

	describe('clean', function() {
		it('remove all existing migrations', function(done) {
			migrator.getAllMigrationNames(function(err, allNames) {
				if (err) done(err);
				allNames.forEach(function(name) {
					migrator.remove(name);
				});
				done();
			});
		});

		it('unmark all executed', function(done) {
			migrator.adapter.getExecutedMigrationNames(function(err, executedNames) {
				if (err) done(err);
				if (!executedNames.length) return done();

				var funcs = executedNames.map(function(name, index) {
					return function() {
						migrator.adapter.unmarkExecuted(name, function(err) {
							if (err) done(err);
							if (index < funcs.length - 1) funcs[++index]();
						});
					};
				});
				funcs.push(done);
				funcs[0]();
			});
		});
	});

	var baseNames = ['first', 'second', 'third', 'second'];
	var names = [];

	describe('create', function() {
		it('expect create without errors', function(done) {
			var funcs = baseNames.map(function(baseName, index) {
				return function() {
					migrator.create(baseName, function(err, name) {
						if (err) done(err);
						names.push(name);
						if (index < funcs.length - 1) funcs[++index]();
					});
				};
			});
			funcs.push(done);
			funcs[0]();
		});

		it('expect that created migrations are exists', function(done) {
			migrator.checkMigrationsExists(names, done);
		});

		it('and loadable', function(done) {
			var loadedCount = 0;
			names.forEach(function(name) {
				migrator.loadMigration(name, function(err, migration) {
					if (err) done(err);
					loadedCount++;
					if (loadedCount == names.length) done();
				});
			});
		});

		it('and lists as `new`', function(done) {
			migrator.getNewMigrationNames(function(err, newNames) {
				if (err) done(err);
				expect(newNames).eql(names);
				done();
			});
		});
	});

	describe('execute', function() {
		it('execute first of them without errors', function(done) {
			migrator.loadMigration(names[0], function(err, migration) {
				if (err) done(err);
				migrator.migrate(migration, done);
			});
		});

		it('expect that it lists as `executed`', function(done) {
			migrator.adapter.getExecutedMigrationNames(function(err, executedNames) {
				if (err) done(err);
				expect(executedNames).eql([names[0]]);
				done();
			});
		});

		it(
			'execution of the same migration (as `migrate --force` do) ' +
			'should passes without errors',
			function(done) {
				migrator.loadMigration(names[0], function(err, migration) {
					if (err) done(err);
					migrator.migrate(migration, done);
				});
			}
		);
	});

	describe('rollback', function() {
		it('rollback which one that was executed without errors', function(done) {
			migrator.loadMigration(names[0], function(err, migration) {
				if (err) done(err);
				migrator.rollback(migration, done);
			});
		});

		it('expect that no `executed` migration at list', function(done) {
			migrator.adapter.getExecutedMigrationNames(function(err, executedNames) {
				if (err) done(err);
				expect(executedNames).have.length(0);
				done();
			});
		});

		it('expect that all migrations lists as `new` again', function(done) {
			migrator.getNewMigrationNames(function(err, newNames) {
				if (err) done(err);
				expect(newNames).eql(names);
				done();
			});
		});
	});

	describe('names normalization', function() {
		it('by path should be ok', function(done) {
			var name = names[0],
				path = Path.join('migrations', name);
			migrator.normalizeNames([name], function(err, normalizedNames) {
				if (err) done(err);
				expect(normalizedNames[0]).equal(name);
				done();
			});
		});

		it('by full name should be ok', function(done) {
			var name = names[0];
			migrator.normalizeNames([name], function(err, normalizedNames) {
				if (err) done(err);
				expect(normalizedNames[0]).equal(name);
				done();
			});
		});

		it('by number should be ok', function(done) {
			var number = 1,
				name = names[0];
			migrator.normalizeNames([number], function(err, normalizedNames) {
				if (err) done(err);
				expect(normalizedNames[0]).equal(name);
				done();
			});
		});

		it('by basename should be ok', function(done) {
			var baseName = baseNames[0],
				name = names[0];
			migrator.normalizeNames([baseName], function(err, normalizedNames) {
				if (err) done(err);
				expect(normalizedNames[0]).equal(name);
				done();
			});
		});

		it('by ambiguous basename should return an error', function(done) {
			var baseName = baseNames[1];
			migrator.normalizeNames([baseName], function(err, normalizedNames) {
				expect(err).ok();
				expect(err).an(Error);
				expect(err.message).contain(
					'Specified migration name `' + baseName + '` is ambiguous'
				);
				done();
			});
		});
	});

	describe('remove', function() {
		it('expect remove without errors', function(done) {
			names.forEach(function(name) {
				return migrator.remove(name);
			});
			done();
		});
	});

	var migration = {};
	migration.name = '9999_test';
	migration.migrate = function(client, done) {
		done();
	};
	migration.rollback = function(client, done) {
		done();
	};

	describe('validate', function() {
		it('valid migration should be ok', function(done) {
			migrator.validateMigration(migration, done);
		});
	});

	['migrate', 'rollback'].forEach(function(action) {
		describe(action, function() {
			it('good migration should be ok', function(done) {
				migrator[action](migration, done);
			});

			it('migration which produce eror should pass it', function(done) {
				migration[action] = function(client, done) {
					done(new Error('Test ' + action + ' error'));
				};
				migrator[action](migration, function(err) {
					expect(err).ok();
					expect(err).a(Error);
					expect(err).have.property(
						'message', 'Test ' + action + ' error'
					);
					done();
				});
			});
		});
	});
});
<commit_msg>check that migration mark as executed after migrate with force at tests<commit_after>'use strict';

var expect = require('expect.js'),
	Migrator = require('../lib/migrator'),
	Path = require('path');

describe('migrator', function() {
	var migrator = new Migrator();

	it('connect', function(done) {
		migrator.connect(done);
	});

	describe('adapter', function() {
		var tryLoad,
			mockAdapter = function() {
				this.getTemplatePath = function() {};
			};

		before(function() {
			tryLoad = Migrator.prototype._tryLoadAdapter;
		});

		it('expect be loaded migrator-related first and than CWD-related', function(done) {
			var paths = [];
			Migrator.prototype._tryLoadAdapter = function(path) {
				paths.push(path);
				return paths.length === 2 ? mockAdapter : new Error('Whatever.');
			};

			new Migrator({
				adapter: 'X'
			});

			expect(paths[0]).eql('X');
			expect(paths[1].substr(-2, 2)).eql('/X');
			done();
		});

		it('expect to throw when both paths can not be resolved', function(done) {
			Migrator.prototype._tryLoadAdapter = function() {
				return new Error('Whatever.');
			};

			expect(function() {
				new Migrator({
					adapter: 'X'
				});
			}).to.throwError(/Whatever./);
			done();
		});

		after(function() {
			Migrator.prototype._tryLoadAdapter = tryLoad;
		});
	});

	describe('clean', function() {
		it('remove all existing migrations', function(done) {
			migrator.getAllMigrationNames(function(err, allNames) {
				if (err) done(err);
				allNames.forEach(function(name) {
					migrator.remove(name);
				});
				done();
			});
		});

		it('unmark all executed', function(done) {
			migrator.adapter.getExecutedMigrationNames(function(err, executedNames) {
				if (err) done(err);
				if (!executedNames.length) return done();

				var funcs = executedNames.map(function(name, index) {
					return function() {
						migrator.adapter.unmarkExecuted(name, function(err) {
							if (err) done(err);
							if (index < funcs.length - 1) funcs[++index]();
						});
					};
				});
				funcs.push(done);
				funcs[0]();
			});
		});
	});

	var baseNames = ['first', 'second', 'third', 'second'];
	var names = [];

	describe('create', function() {
		it('expect create without errors', function(done) {
			var funcs = baseNames.map(function(baseName, index) {
				return function() {
					migrator.create(baseName, function(err, name) {
						if (err) done(err);
						names.push(name);
						if (index < funcs.length - 1) funcs[++index]();
					});
				};
			});
			funcs.push(done);
			funcs[0]();
		});

		it('expect that created migrations are exists', function(done) {
			migrator.checkMigrationsExists(names, done);
		});

		it('and loadable', function(done) {
			var loadedCount = 0;
			names.forEach(function(name) {
				migrator.loadMigration(name, function(err, migration) {
					if (err) done(err);
					loadedCount++;
					if (loadedCount == names.length) done();
				});
			});
		});

		it('and lists as `new`', function(done) {
			migrator.getNewMigrationNames(function(err, newNames) {
				if (err) done(err);
				expect(newNames).eql(names);
				done();
			});
		});
	});

	describe('execute', function() {
		it('execute first of them without errors', function(done) {
			migrator.loadMigration(names[0], function(err, migration) {
				if (err) done(err);
				migrator.migrate(migration, done);
			});
		});

		it('expect that it lists as `executed`', function(done) {
			migrator.adapter.getExecutedMigrationNames(function(err, executedNames) {
				if (err) done(err);
				expect(executedNames).eql([names[0]]);
				done();
			});
		});

		it(
			'execution of the same migration (as `migrate --force` do) ' +
			'should passes without errors',
			function(done) {
				migrator.loadMigration(names[0], function(err, migration) {
					if (err) done(err);
					migrator.migrate(migration, done);
				});
			}
		);

		it('expect that it still lists as `executed`', function(done) {
			migrator.adapter.getExecutedMigrationNames(function(err, executedNames) {
				if (err) done(err);
				expect(executedNames).eql([names[0]]);
				done();
			});
		});
	});

	describe('rollback', function() {
		it('rollback which one that was executed without errors', function(done) {
			migrator.loadMigration(names[0], function(err, migration) {
				if (err) done(err);
				migrator.rollback(migration, done);
			});
		});

		it('expect that no `executed` migration at list', function(done) {
			migrator.adapter.getExecutedMigrationNames(function(err, executedNames) {
				if (err) done(err);
				expect(executedNames).have.length(0);
				done();
			});
		});

		it('expect that all migrations lists as `new` again', function(done) {
			migrator.getNewMigrationNames(function(err, newNames) {
				if (err) done(err);
				expect(newNames).eql(names);
				done();
			});
		});
	});

	describe('names normalization', function() {
		it('by path should be ok', function(done) {
			var name = names[0],
				path = Path.join('migrations', name);
			migrator.normalizeNames([name], function(err, normalizedNames) {
				if (err) done(err);
				expect(normalizedNames[0]).equal(name);
				done();
			});
		});

		it('by full name should be ok', function(done) {
			var name = names[0];
			migrator.normalizeNames([name], function(err, normalizedNames) {
				if (err) done(err);
				expect(normalizedNames[0]).equal(name);
				done();
			});
		});

		it('by number should be ok', function(done) {
			var number = 1,
				name = names[0];
			migrator.normalizeNames([number], function(err, normalizedNames) {
				if (err) done(err);
				expect(normalizedNames[0]).equal(name);
				done();
			});
		});

		it('by basename should be ok', function(done) {
			var baseName = baseNames[0],
				name = names[0];
			migrator.normalizeNames([baseName], function(err, normalizedNames) {
				if (err) done(err);
				expect(normalizedNames[0]).equal(name);
				done();
			});
		});

		it('by ambiguous basename should return an error', function(done) {
			var baseName = baseNames[1];
			migrator.normalizeNames([baseName], function(err, normalizedNames) {
				expect(err).ok();
				expect(err).an(Error);
				expect(err.message).contain(
					'Specified migration name `' + baseName + '` is ambiguous'
				);
				done();
			});
		});
	});

	describe('remove', function() {
		it('expect remove without errors', function(done) {
			names.forEach(function(name) {
				return migrator.remove(name);
			});
			done();
		});
	});

	var migration = {};
	migration.name = '9999_test';
	migration.migrate = function(client, done) {
		done();
	};
	migration.rollback = function(client, done) {
		done();
	};

	describe('validate', function() {
		it('valid migration should be ok', function(done) {
			migrator.validateMigration(migration, done);
		});
	});

	['migrate', 'rollback'].forEach(function(action) {
		describe(action, function() {
			it('good migration should be ok', function(done) {
				migrator[action](migration, done);
			});

			it('migration which produce eror should pass it', function(done) {
				migration[action] = function(client, done) {
					done(new Error('Test ' + action + ' error'));
				};
				migrator[action](migration, function(err) {
					expect(err).ok();
					expect(err).a(Error);
					expect(err).have.property(
						'message', 'Test ' + action + ' error'
					);
					done();
				});
			});
		});
	});
});
<|endoftext|>


<commit_before>/* exported ampInvalidUrlPostEditScreen */

var ampInvalidUrlPostEditScreen = ( function() { // eslint-disable-line no-unused-vars
	var component;

	component = {
		data: {
			l10n: {
				unsaved_changes: '',
				showing_number_errors: '',
				page_heading: '',
				show_all: ''
			}
		}
	};

	/**
	 * The id for the 'Showing x of y errors' notice.
	 *
	 * @var {string}
	 */
	component.idNumberErrors = 'number-errors';

	/**
	 * The id for the 'Show all' button.
	 *
	 * @var {string}
	 */
	component.showAllId = 'show-all-errors';

	/**
	 * Boot.
	 *
	 * @param {Object} data Data.
	 * @param {Object} data.l10n Translations.
	 */
	component.boot = function boot( data ) {
		Object.assign( component.data, data );
		component.handleShowAll();
		component.handleFiltering();
		component.handleSearching();
		component.handleStatusChange();
		component.handleBulkActions();
		component.changeHeading();
		component.watchForUnsavedChanges();
	};

	/**
	 * Add prompt when leaving page due to unsaved changes.
	 */
	component.addBeforeUnloadPrompt = function addBeforeUnloadPrompt() {
		if ( component.beforeUnloadPromptAdded ) {
			return;
		}
		window.addEventListener( 'beforeunload', component.onBeforeUnload );

		// Remove prompt when clicking trash or update.
		document.querySelector( '#major-publishing-actions' ).addEventListener( 'click', function() {
			window.removeEventListener( 'beforeunload', component.onBeforeUnload );
		} );

		component.beforeUnloadPromptAdded = true;
	};

	/**
	 * Watch for unsaved changes.
	 *
	 * Add an beforeunload warning when attempting to leave the page when there are unsaved changes,
	 * unless the user is pressing the trash link or update button.
	 */
	component.watchForUnsavedChanges = function watchForUnsavedChanges() {
		const onChange = function( event ) {
			if ( event.target.matches( 'select' ) ) {
				document.getElementById( 'post' ).removeEventListener( 'change', onChange );
				component.addBeforeUnloadPrompt();
			}
		};
		document.getElementById( 'post' ).addEventListener( 'change', onChange );
	};

	/**
	 * Show message at beforeunload.
	 *
	 * @param {Event} event - The beforeunload event.
	 * @return {string} Message.
	 */
	component.onBeforeUnload = function onBeforeUnload( event ) {
		event.preventDefault();
		event.returnValue = component.data.l10n.unsaved_changes;
		return component.data.l10n.unsaved_changes;
	};

	/**
	 * Updates the <tr> with 'Showing x of y validation errors' at the top of the list table with the current count.
	 * If this does not exist yet, it creates the element.
	 *
	 * @param {number} numberErrorsDisplaying - The number of errors displaying.
	 * @param {number} totalErrors - The total number of errors, displaying or not.
	 */
	component.updateShowingErrorsRow = function updateShowingErrorsRow( numberErrorsDisplaying, totalErrors ) {
		const showAllButton = document.getElementById( component.showAllId );
		let thead, th,
			tr = document.getElementById( component.idNumberErrors );
		const theadQuery = document.getElementsByTagName( 'thead' );

		// Only create the <tr> if it does not exist yet.
		if ( theadQuery[ 0 ] && ! tr ) {
			thead = theadQuery[ 0 ];
			tr = document.createElement( 'tr' );
			th = document.createElement( 'th' );
			th.setAttribute( 'id', component.idNumberErrors );
			th.setAttribute( 'colspan', '6' );
			tr.appendChild( th );
			thead.appendChild( tr );
		}

		// If all of the errors are displaying, hide the 'Show all' button and the count notice.
		if ( showAllButton && numberErrorsDisplaying === totalErrors ) {
			showAllButton.classList.add( 'hidden' );
			tr.classList.add( 'hidden' );
		} else if ( null !== numberErrorsDisplaying ) {
			// Update the number of errors displaying and create a 'Show all' button if it does not exist yet.
			document.getElementById( component.idNumberErrors ).innerText = component.data.l10n.showing_number_errors.replace( '%', numberErrorsDisplaying );
			document.getElementById( component.idNumberErrors ).classList.remove( 'hidden' );
			component.conditionallyCreateShowAllButton();
			if ( document.getElementById( component.showAllId ) ) {
				document.getElementById( component.showAllId ).classList.remove( 'hidden' );
			}
		}
	};

	/**
	 * Conditionally creates and appends a 'Show all' button.
	 */
	component.conditionallyCreateShowAllButton = function conditionallyCreateShowAllButton() {
		const buttonContainer = document.getElementById( 'url-post-filter' );
		let showAllButton = document.getElementById( component.showAllId );

		// There is no 'Show all' <button> yet, but there is a container element for it, create the <button>
		if ( ! showAllButton && buttonContainer ) {
			showAllButton = document.createElement( 'button' );
			showAllButton.id = component.showAllId;
			showAllButton.classList.add( 'button' );
			showAllButton.innerText = component.data.l10n.show_all;
			buttonContainer.appendChild( showAllButton );
		}
	};

	/**
	 * On clicking the 'Show all' <button>, this displays all of the validation errors.
	 * Then, it hides this 'Show all' <button> and the notice for the number of errors showing.
	 */
	component.handleShowAll = function handleShowAll() {
		const onClick = function( event ) {
			const validationErrors = document.querySelectorAll( '[data-error-type]' );
			if ( ! event.target.matches( '#' + component.showAllId ) ) {
				return;
			}
			event.preventDefault();

			// Iterate through all of the errors, and remove the 'hidden' class.
			validationErrors.forEach( function( element ) {
				element.parentElement.parentElement.classList.remove( 'hidden' );
			} );

			/*
			 * Update the notice to indicate that all of the errors are displaying.
			 * Like 'Showing 5 of 5 validation errors'.
 			 */
			component.updateShowingErrorsRow( validationErrors.length, validationErrors.length );

			// Hide this 'Show all' button.
			event.target.classList.add( 'hidden' );

			// Change the value of the error type <select> element to 'All Error Types'.
			document.getElementById( 'amp_validation_error_type' ).selectedIndex = 0;
		};

		document.getElementById( 'url-post-filter' ).addEventListener( 'click', onClick );
	};

	/**
	 * Handles filtering by error type, triggered by clicking 'Apply Filter'.
	 *
	 * Gets the value of the error type <select> element.
	 * And hides all <tr> elements that do not have the same type of this value.
	 * If 'All Error Types' is selected, this displays all errors.
	 */
	component.handleFiltering = function handleFiltering() {
		const onChange = function( event ) {
			const showAllButton = document.getElementById( component.showAllId );
			if ( ! event.target.matches( 'select' ) ) {
				return;
			}

			event.preventDefault();

			const isAllErrorTypesSelected = ( '-1' === event.target.value );
			const errorTypeQuery = document.querySelectorAll( '[data-error-type]' );

			// If the user has chosen 'All Error Types' from the <select>, hide the 'Show all' button.
			if ( isAllErrorTypesSelected && showAllButton ) {
				showAllButton.classList.add( 'hidden' );
			}

			/*
			 * Iterate through all of the <tr> elements in the list table.
			 * If the error type does not match the value (selected error type), hide them.
			 */
			let numberErrorsDisplaying = 0;
			errorTypeQuery.forEach( function( element ) {
				const errorType = element.getAttribute( 'data-error-type' );

				// If 'All Error Types' was selected, this should display all errors.
				if ( isAllErrorTypesSelected || ! event.target.value || event.target.value === errorType ) {
					element.parentElement.parentElement.classList.remove( 'hidden' );
					numberErrorsDisplaying++;
				} else {
					element.parentElement.parentElement.classList.add( 'hidden' );
				}
			} );

			component.updateShowingErrorsRow( numberErrorsDisplaying, errorTypeQuery.length );
		};

		document.getElementById( 'amp_validation_error_type' ).addEventListener( 'change', onChange );
	};

	/**
	 * Handles searching for errors via the <input> and the 'Search Errors' <button>.
	 */
	component.handleSearching = function handleSearching() {
		const onClick = function( event ) {
			event.preventDefault();
			if ( ! event.target.matches( 'input' ) ) {
				return;
			}

			const searchQuery = document.getElementById( 'invalid-url-search-search-input' ).value;
			const detailsQuery = document.querySelectorAll( 'tbody .column-details' );

			/*
			 * Iterate through the 'Details' column of each row.
			 * If the search query is not present, hide the row.
			 */
			let numberErrorsDisplaying = 0;
			detailsQuery.forEach( function( element ) {
				let isSearchQueryPresent = false;

				element.querySelectorAll( '.detailed' ).forEach( function( detailed ) {
					if ( -1 !== detailed.innerText.indexOf( searchQuery ) ) {
						isSearchQueryPresent = true;
					}
				} );

				if ( isSearchQueryPresent ) {
					element.parentElement.classList.remove( 'hidden' );
					numberErrorsDisplaying++;
				} else {
					element.parentElement.classList.add( 'hidden' );
				}
			} );

			component.updateShowingErrorsRow( numberErrorsDisplaying, detailsQuery.length );
		};

		document.getElementById( 'search-submit' ).addEventListener( 'click', onClick );
	};

	/**
	 * Update icon for select element.
	 *
	 * @param {HTMLSelectElement} select Select element.
	 */
	component.updateSelectIcon = function updateSelectIcon( select ) {
		const newOption = select.options[ select.selectedIndex ];
		if ( newOption ) {
			const iconSrc = newOption.getAttribute( 'data-status-icon' );
			select.parentNode.querySelector( 'img' ).setAttribute( 'src', iconSrc );
		}
	};

	/**
	 * Handles a change in the error status, like from 'New' to 'Accepted'.
	 *
	 * Gets the data-status-icon value from the newly-selected <option>.
	 * And sets this as the src of the status icon <img>.
	 */
	component.handleStatusChange = function handleStatusChange() {
		const setRowStatusClass = function( { row, select } ) {
			const statusText = select.options[ select.selectedIndex ].innerText.trim();

			if ( statusText ) {
				row.classList.toggle( 'new', 'New Rejected' === statusText || 'New Accepted' === statusText );
				row.classList.toggle( 'accepted', 'Accepted' === statusText );
				row.classList.toggle( 'rejected', 'Rejected' === statusText );
			}
		};

		const onChange = function( { event, row, select } ) {
			if ( event.target.matches( 'select' ) ) {
				component.updateSelectIcon( event.target );
				setRowStatusClass( { row, select } );
			}
		};

		document.querySelectorAll( 'tr[id^="tag-"]' ).forEach( function( row ) {
			const select = row.querySelector( '.amp-validation-error-status' );

			if ( select ) {
				setRowStatusClass( { row, select } );
				select.addEventListener( 'change', function( event ) {
					onChange( { event, row, select } );
				} );
			}
		} );
	};

	/**
	 * On checking a bulk action checkbox, this ensures that the 'Accept' and 'Reject' buttons are present. Handle clicking on buttons.
	 *
	 * They're hidden until one of these boxes is checked.
	 * Also, on unchecking the last checked box, this hides these buttons.
	 */
	component.handleBulkActions = function handleBulkActions() {
		const acceptButton = document.querySelector( 'button.action.accept' );
		const rejectButton = document.querySelector( 'button.action.reject' );

		const onChange = function( event ) {
			let areThereCheckedBoxes;

			if ( ! event.target.matches( '[type=checkbox]' ) ) {
				return;
			}

			if ( event.target.checked ) {
				// This checkbox was checked, so ensure the buttons display.
				acceptButton.classList.remove( 'hidden' );
				rejectButton.classList.remove( 'hidden' );
			} else {
				/*
				 * This checkbox was unchecked.
				 * So find if there are any other checkboxes that are checked.
				 * If not, hide the 'Accept' and 'Reject' buttons.
				 */
				areThereCheckedBoxes = false;
				document.querySelectorAll( '.check-column [type=checkbox]' ).forEach( function( element ) {
					if ( element.checked ) {
						areThereCheckedBoxes = true;
					}
				} );
				if ( ! areThereCheckedBoxes ) {
					acceptButton.classList.add( 'hidden' );
					rejectButton.classList.add( 'hidden' );
				}
			}
		};

		document.querySelectorAll( '.check-column [type=checkbox]' ).forEach( function( element ) {
			element.addEventListener( 'change', onChange );
		} );

		// Handle click on accept button.
		acceptButton.addEventListener( 'click', function() {
			Array.prototype.forEach.call( document.querySelectorAll( 'select.amp-validation-error-status' ), function( select ) {
				if ( select.closest( 'tr' ).querySelector( '.check-column input[type=checkbox]' ).checked ) {
					select.value = '3';
					component.updateSelectIcon( select );
					component.addBeforeUnloadPrompt();
				}
			} );
		} );

		// Handle click on reject button.
		rejectButton.addEventListener( 'click', function() {
			Array.prototype.forEach.call( document.querySelectorAll( 'select.amp-validation-error-status' ), function( select ) {
				if ( select.closest( 'tr' ).querySelector( '.check-column input[type=checkbox]' ).checked ) {
					select.value = '2';
					component.updateSelectIcon( select );
					component.addBeforeUnloadPrompt();
				}
			} );
		} );
	};

	/**
	 * Changes the page heading and document title, as this doesn't look to be possible with a PHP filter.
	 */
	component.changeHeading = function changeHeading() {
		const headingQuery = document.getElementsByClassName( 'wp-heading-inline' );
		if ( headingQuery[ 0 ] && component.data.l10n.page_heading ) {
			headingQuery[ 0 ].innerText = component.data.l10n.page_heading;
			document.title = component.data.l10n.page_heading + document.title;
		}
	};

	return component;
}() );
<commit_msg>Check value instead of innerText to set row classes<commit_after>/* exported ampInvalidUrlPostEditScreen */

const ampInvalidUrlPostEditScreen = ( function() { // eslint-disable-line no-unused-vars
	let component = {
		data: {
			l10n: {
				unsaved_changes: '',
				showing_number_errors: '',
				page_heading: '',
				show_all: ''
			}
		}
	};

	/**
	 * The id for the 'Showing x of y errors' notice.
	 *
	 * @var {string}
	 */
	component.idNumberErrors = 'number-errors';

	/**
	 * The id for the 'Show all' button.
	 *
	 * @var {string}
	 */
	component.showAllId = 'show-all-errors';

	/**
	 * Boot.
	 *
	 * @param {Object} data Data.
	 * @param {Object} data.l10n Translations.
	 */
	component.boot = function boot( data ) {
		Object.assign( component.data, data );
		component.handleShowAll();
		component.handleFiltering();
		component.handleSearching();
		component.handleStatusChange();
		component.handleBulkActions();
		component.changeHeading();
		component.watchForUnsavedChanges();
	};

	/**
	 * Add prompt when leaving page due to unsaved changes.
	 */
	component.addBeforeUnloadPrompt = function addBeforeUnloadPrompt() {
		if ( component.beforeUnloadPromptAdded ) {
			return;
		}
		window.addEventListener( 'beforeunload', component.onBeforeUnload );

		// Remove prompt when clicking trash or update.
		document.querySelector( '#major-publishing-actions' ).addEventListener( 'click', function() {
			window.removeEventListener( 'beforeunload', component.onBeforeUnload );
		} );

		component.beforeUnloadPromptAdded = true;
	};

	/**
	 * Watch for unsaved changes.
	 *
	 * Add an beforeunload warning when attempting to leave the page when there are unsaved changes,
	 * unless the user is pressing the trash link or update button.
	 */
	component.watchForUnsavedChanges = function watchForUnsavedChanges() {
		const onChange = function( event ) {
			if ( event.target.matches( 'select' ) ) {
				document.getElementById( 'post' ).removeEventListener( 'change', onChange );
				component.addBeforeUnloadPrompt();
			}
		};
		document.getElementById( 'post' ).addEventListener( 'change', onChange );
	};

	/**
	 * Show message at beforeunload.
	 *
	 * @param {Event} event - The beforeunload event.
	 * @return {string} Message.
	 */
	component.onBeforeUnload = function onBeforeUnload( event ) {
		event.preventDefault();
		event.returnValue = component.data.l10n.unsaved_changes;
		return component.data.l10n.unsaved_changes;
	};

	/**
	 * Updates the <tr> with 'Showing x of y validation errors' at the top of the list table with the current count.
	 * If this does not exist yet, it creates the element.
	 *
	 * @param {number} numberErrorsDisplaying - The number of errors displaying.
	 * @param {number} totalErrors - The total number of errors, displaying or not.
	 */
	component.updateShowingErrorsRow = function updateShowingErrorsRow( numberErrorsDisplaying, totalErrors ) {
		const showAllButton = document.getElementById( component.showAllId );
		let thead, th,
			tr = document.getElementById( component.idNumberErrors );
		const theadQuery = document.getElementsByTagName( 'thead' );

		// Only create the <tr> if it does not exist yet.
		if ( theadQuery[ 0 ] && ! tr ) {
			thead = theadQuery[ 0 ];
			tr = document.createElement( 'tr' );
			th = document.createElement( 'th' );
			th.setAttribute( 'id', component.idNumberErrors );
			th.setAttribute( 'colspan', '6' );
			tr.appendChild( th );
			thead.appendChild( tr );
		}

		// If all of the errors are displaying, hide the 'Show all' button and the count notice.
		if ( showAllButton && numberErrorsDisplaying === totalErrors ) {
			showAllButton.classList.add( 'hidden' );
			tr.classList.add( 'hidden' );
		} else if ( null !== numberErrorsDisplaying ) {
			// Update the number of errors displaying and create a 'Show all' button if it does not exist yet.
			document.getElementById( component.idNumberErrors ).innerText = component.data.l10n.showing_number_errors.replace( '%', numberErrorsDisplaying );
			document.getElementById( component.idNumberErrors ).classList.remove( 'hidden' );
			component.conditionallyCreateShowAllButton();
			if ( document.getElementById( component.showAllId ) ) {
				document.getElementById( component.showAllId ).classList.remove( 'hidden' );
			}
		}
	};

	/**
	 * Conditionally creates and appends a 'Show all' button.
	 */
	component.conditionallyCreateShowAllButton = function conditionallyCreateShowAllButton() {
		const buttonContainer = document.getElementById( 'url-post-filter' );
		let showAllButton = document.getElementById( component.showAllId );

		// There is no 'Show all' <button> yet, but there is a container element for it, create the <button>
		if ( ! showAllButton && buttonContainer ) {
			showAllButton = document.createElement( 'button' );
			showAllButton.id = component.showAllId;
			showAllButton.classList.add( 'button' );
			showAllButton.innerText = component.data.l10n.show_all;
			buttonContainer.appendChild( showAllButton );
		}
	};

	/**
	 * On clicking the 'Show all' <button>, this displays all of the validation errors.
	 * Then, it hides this 'Show all' <button> and the notice for the number of errors showing.
	 */
	component.handleShowAll = function handleShowAll() {
		const onClick = function( event ) {
			const validationErrors = document.querySelectorAll( '[data-error-type]' );
			if ( ! event.target.matches( '#' + component.showAllId ) ) {
				return;
			}
			event.preventDefault();

			// Iterate through all of the errors, and remove the 'hidden' class.
			validationErrors.forEach( function( element ) {
				element.parentElement.parentElement.classList.remove( 'hidden' );
			} );

			/*
			 * Update the notice to indicate that all of the errors are displaying.
			 * Like 'Showing 5 of 5 validation errors'.
 			 */
			component.updateShowingErrorsRow( validationErrors.length, validationErrors.length );

			// Hide this 'Show all' button.
			event.target.classList.add( 'hidden' );

			// Change the value of the error type <select> element to 'All Error Types'.
			document.getElementById( 'amp_validation_error_type' ).selectedIndex = 0;
		};

		document.getElementById( 'url-post-filter' ).addEventListener( 'click', onClick );
	};

	/**
	 * Handles filtering by error type, triggered by clicking 'Apply Filter'.
	 *
	 * Gets the value of the error type <select> element.
	 * And hides all <tr> elements that do not have the same type of this value.
	 * If 'All Error Types' is selected, this displays all errors.
	 */
	component.handleFiltering = function handleFiltering() {
		const onChange = function( event ) {
			const showAllButton = document.getElementById( component.showAllId );
			if ( ! event.target.matches( 'select' ) ) {
				return;
			}

			event.preventDefault();

			const isAllErrorTypesSelected = ( '-1' === event.target.value );
			const errorTypeQuery = document.querySelectorAll( '[data-error-type]' );

			// If the user has chosen 'All Error Types' from the <select>, hide the 'Show all' button.
			if ( isAllErrorTypesSelected && showAllButton ) {
				showAllButton.classList.add( 'hidden' );
			}

			/*
			 * Iterate through all of the <tr> elements in the list table.
			 * If the error type does not match the value (selected error type), hide them.
			 */
			let numberErrorsDisplaying = 0;
			errorTypeQuery.forEach( function( element ) {
				const errorType = element.getAttribute( 'data-error-type' );

				// If 'All Error Types' was selected, this should display all errors.
				if ( isAllErrorTypesSelected || ! event.target.value || event.target.value === errorType ) {
					element.parentElement.parentElement.classList.remove( 'hidden' );
					numberErrorsDisplaying++;
				} else {
					element.parentElement.parentElement.classList.add( 'hidden' );
				}
			} );

			component.updateShowingErrorsRow( numberErrorsDisplaying, errorTypeQuery.length );
		};

		document.getElementById( 'amp_validation_error_type' ).addEventListener( 'change', onChange );
	};

	/**
	 * Handles searching for errors via the <input> and the 'Search Errors' <button>.
	 */
	component.handleSearching = function handleSearching() {
		const onClick = function( event ) {
			event.preventDefault();
			if ( ! event.target.matches( 'input' ) ) {
				return;
			}

			const searchQuery = document.getElementById( 'invalid-url-search-search-input' ).value;
			const detailsQuery = document.querySelectorAll( 'tbody .column-details' );

			/*
			 * Iterate through the 'Details' column of each row.
			 * If the search query is not present, hide the row.
			 */
			let numberErrorsDisplaying = 0;
			detailsQuery.forEach( function( element ) {
				let isSearchQueryPresent = false;

				element.querySelectorAll( '.detailed' ).forEach( function( detailed ) {
					if ( -1 !== detailed.innerText.indexOf( searchQuery ) ) {
						isSearchQueryPresent = true;
					}
				} );

				if ( isSearchQueryPresent ) {
					element.parentElement.classList.remove( 'hidden' );
					numberErrorsDisplaying++;
				} else {
					element.parentElement.classList.add( 'hidden' );
				}
			} );

			component.updateShowingErrorsRow( numberErrorsDisplaying, detailsQuery.length );
		};

		document.getElementById( 'search-submit' ).addEventListener( 'click', onClick );
	};

	/**
	 * Update icon for select element.
	 *
	 * @param {HTMLSelectElement} select Select element.
	 */
	component.updateSelectIcon = function updateSelectIcon( select ) {
		const newOption = select.options[ select.selectedIndex ];
		if ( newOption ) {
			const iconSrc = newOption.getAttribute( 'data-status-icon' );
			select.parentNode.querySelector( 'img' ).setAttribute( 'src', iconSrc );
		}
	};

	/**
	 * Handles a change in the error status, like from 'New' to 'Accepted'.
	 *
	 * Gets the data-status-icon value from the newly-selected <option>.
	 * And sets this as the src of the status icon <img>.
	 */
	component.handleStatusChange = function handleStatusChange() {
		const setRowStatusClass = function( { row, select } ) {
			const acceptedValue = 3,
				rejectedValue = 2;
			let status = parseInt( select.options[ select.selectedIndex ].value );

			row.classList.toggle( 'new', isNaN( status ) );
			row.classList.toggle( 'accepted', acceptedValue === status );
			row.classList.toggle( 'rejected', rejectedValue === status );
		};

		const onChange = function( { event, row, select } ) {
			if ( event.target.matches( 'select' ) ) {
				component.updateSelectIcon( event.target );
				setRowStatusClass( { row, select } );
			}
		};

		document.querySelectorAll( 'tr[id^="tag-"]' ).forEach( function( row ) {
			const select = row.querySelector( '.amp-validation-error-status' );

			if ( select ) {
				setRowStatusClass( { row, select } );
				select.addEventListener( 'change', function( event ) {
					onChange( { event, row, select } );
				} );
			}
		} );
	};

	/**
	 * On checking a bulk action checkbox, this ensures that the 'Accept' and 'Reject' buttons are present. Handle clicking on buttons.
	 *
	 * They're hidden until one of these boxes is checked.
	 * Also, on unchecking the last checked box, this hides these buttons.
	 */
	component.handleBulkActions = function handleBulkActions() {
		const acceptButton = document.querySelector( 'button.action.accept' );
		const rejectButton = document.querySelector( 'button.action.reject' );

		const onChange = function( event ) {
			let areThereCheckedBoxes;

			if ( ! event.target.matches( '[type=checkbox]' ) ) {
				return;
			}

			if ( event.target.checked ) {
				// This checkbox was checked, so ensure the buttons display.
				acceptButton.classList.remove( 'hidden' );
				rejectButton.classList.remove( 'hidden' );
			} else {
				/*
				 * This checkbox was unchecked.
				 * So find if there are any other checkboxes that are checked.
				 * If not, hide the 'Accept' and 'Reject' buttons.
				 */
				areThereCheckedBoxes = false;
				document.querySelectorAll( '.check-column [type=checkbox]' ).forEach( function( element ) {
					if ( element.checked ) {
						areThereCheckedBoxes = true;
					}
				} );
				if ( ! areThereCheckedBoxes ) {
					acceptButton.classList.add( 'hidden' );
					rejectButton.classList.add( 'hidden' );
				}
			}
		};

		document.querySelectorAll( '.check-column [type=checkbox]' ).forEach( function( element ) {
			element.addEventListener( 'change', onChange );
		} );

		// Handle click on accept button.
		acceptButton.addEventListener( 'click', function() {
			Array.prototype.forEach.call( document.querySelectorAll( 'select.amp-validation-error-status' ), function( select ) {
				if ( select.closest( 'tr' ).querySelector( '.check-column input[type=checkbox]' ).checked ) {
					select.value = '3';
					component.updateSelectIcon( select );
					component.addBeforeUnloadPrompt();
				}
			} );
		} );

		// Handle click on reject button.
		rejectButton.addEventListener( 'click', function() {
			Array.prototype.forEach.call( document.querySelectorAll( 'select.amp-validation-error-status' ), function( select ) {
				if ( select.closest( 'tr' ).querySelector( '.check-column input[type=checkbox]' ).checked ) {
					select.value = '2';
					component.updateSelectIcon( select );
					component.addBeforeUnloadPrompt();
				}
			} );
		} );
	};

	/**
	 * Changes the page heading and document title, as this doesn't look to be possible with a PHP filter.
	 */
	component.changeHeading = function changeHeading() {
		const headingQuery = document.getElementsByClassName( 'wp-heading-inline' );
		if ( headingQuery[ 0 ] && component.data.l10n.page_heading ) {
			headingQuery[ 0 ].innerText = component.data.l10n.page_heading;
			document.title = component.data.l10n.page_heading + document.title;
		}
	};

	return component;
}() );
<|endoftext|>


<commit_before>'use strict'

var logger = require('../utils/composrLogger')
var composr = require('composr-core')
var q = require('q')
var https = require('https')
var hub = require('./hub')
var config = require('./config')

var engine = {
  suscribeToCoreEvents: function () {
    engine.composr.events.on('debug', 'CorbelComposr', function () {
      logger.debug.apply(logger, arguments)
    })

    engine.composr.events.on('error', 'CorbelComposr', function () {
      logger.error.apply(logger, arguments)
    })

    engine.composr.events.on('warn', 'CorbelComposr', function () {
      logger.warn.apply(logger, arguments)
    })

    engine.composr.events.on('info', 'CorbelComposr', function () {
      logger.info.apply(logger, arguments)
    })

    engine.composr.events.on('phrase:registered', 'CorbelComposr', function (phrase) {
      hub.emit('create:routes', phrase)
    })
  },

  /* ***********************************************************
   * - Deletes timeout handler
   * - Resolves service checking request if response is sent from server
   * - Rejects service checking request if 'error' evt or timeout while waiting for response
   * @param  {Function} resolve Services to check
   * @param  {Function} reject Timeout before reject promise
   * @param  {String} module service currently checking
   * @param  {Object} promiseTimeoutHandler Timeout handler
   * @return nothing
   *************************************************************/

  resolveOrRejectServiceCheckingRequest: function (resolve, reject, request, module, promiseTimeoutHandler, rejectMessage) {
    if (promiseTimeoutHandler) {
      clearTimeout(promiseTimeoutHandler)
    }
    if (resolve) {
      logger.info('External service', module, 'is UP')
      resolve()
    } else if (reject) {
      rejectMessage = rejectMessage || ''
      logger.error('External service', module, 'is DOWN')
      request.abort()
      reject(rejectMessage)
    }
  },

  /* ***********************************************************
   * - Initializes how a request is made
   * @param  {String} url to send request
   * @param  {Function} to execute when request is successfully replied
   * @param  {Function} to execute when request is not replied
   * @param  {Object} that holds a reference to request
   * @param  {Function} reference to timeout for this request
   * @param  {String} data that server sends
   *************************************************************/

  setUpRequest: function (url, module, resolve, reject, serviceCheckingRequestTimeout) {
    var request = https.get(url, function (res) {
      var responseData = ''
      res.on('data', function (chunk) {
        responseData += chunk
      })
      res.on('end', function () {
        if (engine.resolveOrRejectServiceCheckingRequest) {
          var isValidResponse = (res.statusCode === 200)
          var bodyContainsError = (responseData.indexOf('error') > -1 || responseData.indexOf('err') > -1)
          if (isValidResponse && !bodyContainsError) {
            engine.resolveOrRejectServiceCheckingRequest(resolve, null, request, module, promiseTimeoutHandler, null)
          } else {
            engine.resolveOrRejectServiceCheckingRequest(null, reject, request, module, promiseTimeoutHandler, 'JSON error')
          }
        }
      })
    })
      .on('error', function (err) {
        // resolveOrRejectServiceCheckingRequest === undefined -> Promises is already resolved
        if (engine.resolveOrRejectServiceCheckingRequest) {
          engine.resolveOrRejectServiceCheckingRequest(null, reject, request, module, promiseTimeoutHandler, err)
        }
      })
    var promiseTimeoutHandler = setTimeout(engine.resolveOrRejectServiceCheckingRequest, serviceCheckingRequestTimeout, null, reject, request, module, promiseTimeoutHandler, 'Request timeout fired')
    return request
  },

  /* ***********************************************************
   * - Launches services checking requests
   * @param  {Array} modules Services to check
   * @param  {integer} serviceCheckingRequestTimeout Timeout before reject promise
   * @return {Array} promises
   *************************************************************/

  initServiceCheckingRequests: function (modules, serviceCheckingRequestTimeout) {
    var path = config('corbel.driver.options').urlBase
    return modules.map(function (module) {
      var url
      logger.info('Checking for external service', module)
      return new Promise(function (resolve, reject) {
        url = path.replace('{{module}}', module).replace(/\/(v.+)\//, '/') + 'version'
        engine.setUpRequest(url, module, resolve, reject, serviceCheckingRequestTimeout)
      })
    })
  },

  // Recursivelly wait until all the corbel services are up
  waitTilServicesUp: function () {
    var modules = ['iam', 'resources']
    var serviceCheckingRequestTimeout = config('services.timeout')
    var promises = engine.initServiceCheckingRequests(modules, serviceCheckingRequestTimeout)
    return Promise.all(promises)
  },

  // Returns the credentials for the composr-core initialization
  getComposrCoreCredentials: function () {
    return {
      credentials: {
        clientId: config('corbel.composr.credentials').clientId,
        clientSecret: config('corbel.composr.credentials').clientSecret,
        scopes: config('corbel.composr.credentials').scopes
      },
      urlBase: config('corbel.driver.options').urlBase
    }
  },

  // Inits the composr-core package
  initComposrCore: function (credentials, fetchData) {
    return new Promise(function (resolve, reject) {
      engine.composr.init(credentials, fetchData)
        .then(function () {
          engine.initialized = true
          var msg = fetchData ? 'Engine initialized with data! :)' : 'Engine initialized without data'
          logger.info(msg)
          resolve()
        })
        .catch(function (err) {
          engine.initialized = false
          logger.error('ERROR launching composr, please check your credentials and network')
          reject(err)
        })
    })
  },

  launchTries: function (time, retries) {
    if (!time) {
      time = config('services.time')
    }
    if (!retries) {
      retries = config('services.retries')
    }

    return new Promise(function (resolve, reject) {
      function launch (retries) {
        if (!retries) {
          return reject()
        }
        engine.waitTilServicesUp()
          .then(function () {
            logger.info('All Services up and running!')
            resolve()
          })
          .catch(function () {
            logger.info('Retrying services check after', time * retries, 'milliseconds')
            setTimeout(function () {
              return launch(retries - 1)
            }, time * retries)
          })
      }
      launch(retries)
    })
  },

  /**
   * Launches the bootstrap of data, worker and logger
   * @param  {[type]} app [description]
   * @return promise
   */
  init: function (app) {
    var dfd = q.defer()
    var retries = config('services.retries')
    var fetchData = true

    // Suscribe to log events
    engine.suscribeToCoreEvents()

    engine.launchTries(retries)
      .then(function () {
        engine.initComposrCore(engine.getComposrCoreCredentials(), fetchData)
          .then(function () {
            dfd.resolve({
              app: app,
              composr: engine.composr,
              initialized: engine.initialized
            })
          })
          .catch(dfd.reject)
      })
      .catch(function () {
        engine.initComposrCore(engine.getComposrCoreCredentials(), !fetchData)
          .then(function () {
            dfd.resolve({
              app: app,
              composr: engine.composr,
              initialized: engine.initialized
            })
            logger.info('The server is launched, delaying the fetch data')
          })
          .then(function () {
            tryAgain()
          })
          .catch(dfd.reject)
      })

    function tryAgain () {
      engine.launchTries(retries)
        .then(function () {
          logger.info('Data is available, fetching')
          engine.initComposrCore(engine.getComposrCoreCredentials(), fetchData)
        })
        .catch(function () {
          // If the services were unavailable delay the retries and go on
          logger.error('Services where unaccesible after ' + retries + ' retries')
          tryAgain()
        })
    }
    return dfd.promise
  },

  setWorkerStatus: function (bool) {
    engine.workerStatus = bool
  },

  getWorkerStatus: function () {
    return engine.workerStatus
  }
}

engine.initialized = false
engine.workerStatus = false
engine.phrasesCollection = 'composr:Phrase'
engine.snippetsCollection = 'composr:Snippet'
engine.composr = composr
module.exports = engine
<commit_msg>event for metrics<commit_after>'use strict'

var logger = require('../utils/composrLogger')
var composr = require('composr-core')
var q = require('q')
var https = require('https')
var hub = require('./hub')
var config = require('./config')

var engine = {
  suscribeToCoreEvents: function () {
    engine.composr.events.on('debug', 'CorbelComposr', function () {
      logger.debug.apply(logger, arguments)
    })

    engine.composr.events.on('error', 'CorbelComposr', function () {
      logger.error.apply(logger, arguments)
    })

    engine.composr.events.on('warn', 'CorbelComposr', function () {
      logger.warn.apply(logger, arguments)
    })

    engine.composr.events.on('info', 'CorbelComposr', function () {
      logger.info.apply(logger, arguments)
    })

    engine.composr.events.on('phrase:registered', 'CorbelComposr', function (phrase) {
      hub.emit('create:routes', phrase)
    })

    engine.composr.events.on('metrics', 'CorbelComposr', function (options) {
      //@TODO: implement,
      //options.domain
      //options.data
    })
  },

  /* ***********************************************************
   * - Deletes timeout handler
   * - Resolves service checking request if response is sent from server
   * - Rejects service checking request if 'error' evt or timeout while waiting for response
   * @param  {Function} resolve Services to check
   * @param  {Function} reject Timeout before reject promise
   * @param  {String} module service currently checking
   * @param  {Object} promiseTimeoutHandler Timeout handler
   * @return nothing
   *************************************************************/

  resolveOrRejectServiceCheckingRequest: function (resolve, reject, request, module, promiseTimeoutHandler, rejectMessage) {
    if (promiseTimeoutHandler) {
      clearTimeout(promiseTimeoutHandler)
    }
    if (resolve) {
      logger.info('External service', module, 'is UP')
      resolve()
    } else if (reject) {
      rejectMessage = rejectMessage || ''
      logger.error('External service', module, 'is DOWN')
      request.abort()
      reject(rejectMessage)
    }
  },

  /* ***********************************************************
   * - Initializes how a request is made
   * @param  {String} url to send request
   * @param  {Function} to execute when request is successfully replied
   * @param  {Function} to execute when request is not replied
   * @param  {Object} that holds a reference to request
   * @param  {Function} reference to timeout for this request
   * @param  {String} data that server sends
   *************************************************************/

  setUpRequest: function (url, module, resolve, reject, serviceCheckingRequestTimeout) {
    var request = https.get(url, function (res) {
      var responseData = ''
      res.on('data', function (chunk) {
        responseData += chunk
      })
      res.on('end', function () {
        if (engine.resolveOrRejectServiceCheckingRequest) {
          var isValidResponse = (res.statusCode === 200)
          var bodyContainsError = (responseData.indexOf('error') > -1 || responseData.indexOf('err') > -1)
          if (isValidResponse && !bodyContainsError) {
            engine.resolveOrRejectServiceCheckingRequest(resolve, null, request, module, promiseTimeoutHandler, null)
          } else {
            engine.resolveOrRejectServiceCheckingRequest(null, reject, request, module, promiseTimeoutHandler, 'JSON error')
          }
        }
      })
    })
      .on('error', function (err) {
        // resolveOrRejectServiceCheckingRequest === undefined -> Promises is already resolved
        if (engine.resolveOrRejectServiceCheckingRequest) {
          engine.resolveOrRejectServiceCheckingRequest(null, reject, request, module, promiseTimeoutHandler, err)
        }
      })
    var promiseTimeoutHandler = setTimeout(engine.resolveOrRejectServiceCheckingRequest, serviceCheckingRequestTimeout, null, reject, request, module, promiseTimeoutHandler, 'Request timeout fired')
    return request
  },

  /* ***********************************************************
   * - Launches services checking requests
   * @param  {Array} modules Services to check
   * @param  {integer} serviceCheckingRequestTimeout Timeout before reject promise
   * @return {Array} promises
   *************************************************************/

  initServiceCheckingRequests: function (modules, serviceCheckingRequestTimeout) {
    var path = config('corbel.driver.options').urlBase
    return modules.map(function (module) {
      var url
      logger.info('Checking for external service', module)
      return new Promise(function (resolve, reject) {
        url = path.replace('{{module}}', module).replace(/\/(v.+)\//, '/') + 'version'
        engine.setUpRequest(url, module, resolve, reject, serviceCheckingRequestTimeout)
      })
    })
  },

  // Recursivelly wait until all the corbel services are up
  waitTilServicesUp: function () {
    var modules = ['iam', 'resources']
    var serviceCheckingRequestTimeout = config('services.timeout')
    var promises = engine.initServiceCheckingRequests(modules, serviceCheckingRequestTimeout)
    return Promise.all(promises)
  },

  // Returns the credentials for the composr-core initialization
  getComposrCoreCredentials: function () {
    return {
      credentials: {
        clientId: config('corbel.composr.credentials').clientId,
        clientSecret: config('corbel.composr.credentials').clientSecret,
        scopes: config('corbel.composr.credentials').scopes
      },
      urlBase: config('corbel.driver.options').urlBase
    }
  },

  // Inits the composr-core package
  initComposrCore: function (credentials, fetchData) {
    return new Promise(function (resolve, reject) {
      engine.composr.init(credentials, fetchData)
        .then(function () {
          engine.initialized = true
          var msg = fetchData ? 'Engine initialized with data! :)' : 'Engine initialized without data'
          logger.info(msg)
          resolve()
        })
        .catch(function (err) {
          engine.initialized = false
          logger.error('ERROR launching composr, please check your credentials and network')
          reject(err)
        })
    })
  },

  launchTries: function (time, retries) {
    if (!time) {
      time = config('services.time')
    }
    if (!retries) {
      retries = config('services.retries')
    }

    return new Promise(function (resolve, reject) {
      function launch (retries) {
        if (!retries) {
          return reject()
        }
        engine.waitTilServicesUp()
          .then(function () {
            logger.info('All Services up and running!')
            resolve()
          })
          .catch(function () {
            logger.info('Retrying services check after', time * retries, 'milliseconds')
            setTimeout(function () {
              return launch(retries - 1)
            }, time * retries)
          })
      }
      launch(retries)
    })
  },

  /**
   * Launches the bootstrap of data, worker and logger
   * @param  {[type]} app [description]
   * @return promise
   */
  init: function (app) {
    var dfd = q.defer()
    var retries = config('services.retries')
    var fetchData = true

    // Suscribe to log events
    engine.suscribeToCoreEvents()

    engine.launchTries(retries)
      .then(function () {
        engine.initComposrCore(engine.getComposrCoreCredentials(), fetchData)
          .then(function () {
            dfd.resolve({
              app: app,
              composr: engine.composr,
              initialized: engine.initialized
            })
          })
          .catch(dfd.reject)
      })
      .catch(function () {
        engine.initComposrCore(engine.getComposrCoreCredentials(), !fetchData)
          .then(function () {
            dfd.resolve({
              app: app,
              composr: engine.composr,
              initialized: engine.initialized
            })
            logger.info('The server is launched, delaying the fetch data')
          })
          .then(function () {
            tryAgain()
          })
          .catch(dfd.reject)
      })

    function tryAgain () {
      engine.launchTries(retries)
        .then(function () {
          logger.info('Data is available, fetching')
          engine.initComposrCore(engine.getComposrCoreCredentials(), fetchData)
        })
        .catch(function () {
          // If the services were unavailable delay the retries and go on
          logger.error('Services where unaccesible after ' + retries + ' retries')
          tryAgain()
        })
    }
    return dfd.promise
  },

  setWorkerStatus: function (bool) {
    engine.workerStatus = bool
  },

  getWorkerStatus: function () {
    return engine.workerStatus
  }
}

engine.initialized = false
engine.workerStatus = false
engine.phrasesCollection = 'composr:Phrase'
engine.snippetsCollection = 'composr:Snippet'
engine.composr = composr
module.exports = engine
<|endoftext|>


<commit_before>/**
* Copyright 2012-2020, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var mat3X3 = require('gl-mat3');

exports.init2dArray = function(rowLength, colLength) {
    var array = new Array(rowLength);
    for(var i = 0; i < rowLength; i++) array[i] = new Array(colLength);
    return array;
};

/**
 * transpose a (possibly ragged) 2d array z. inspired by
 * http://stackoverflow.com/questions/17428587/
 * transposing-a-2d-array-in-javascript
 */
exports.transposeRagged = function(z) {
    var maxlen = 0;
    var zlen = z.length;
    var i, j;
    // Maximum row length:
    for(i = 0; i < zlen; i++) maxlen = Math.max(maxlen, z[i].length);

    var t = new Array(maxlen);
    for(i = 0; i < maxlen; i++) {
        t[i] = new Array(zlen);
        for(j = 0; j < zlen; j++) t[i][j] = z[j][i];
    }

    return t;
};

// our own dot function so that we don't need to include numeric
exports.dot = function(x, y) {
    if(!(x.length && y.length) || x.length !== y.length) return null;

    var len = x.length;
    var out;
    var i;

    if(x[0].length) {
        // mat-vec or mat-mat
        out = new Array(len);
        for(i = 0; i < len; i++) out[i] = exports.dot(x[i], y);
    } else if(y[0].length) {
        // vec-mat
        var yTranspose = exports.transposeRagged(y);
        out = new Array(yTranspose.length);
        for(i = 0; i < yTranspose.length; i++) out[i] = exports.dot(x, yTranspose[i]);
    } else {
        // vec-vec
        out = 0;
        for(i = 0; i < len; i++) out += x[i] * y[i];
    }

    return out;
};

// translate by (x,y)
exports.translationMatrix = function(x, y) {
    return [[1, 0, x], [0, 1, y], [0, 0, 1]];
};

// rotate by alpha around (0,0)
exports.rotationMatrix = function(alpha) {
    var a = alpha * Math.PI / 180;
    return [[Math.cos(a), -Math.sin(a), 0],
            [Math.sin(a), Math.cos(a), 0],
            [0, 0, 1]];
};

// rotate by alpha around (x,y)
exports.rotationXYMatrix = function(a, x, y) {
    return exports.dot(
        exports.dot(exports.translationMatrix(x, y),
                    exports.rotationMatrix(a)),
        exports.translationMatrix(-x, -y));
};

// applies a 2D transformation matrix to either x and y params or an [x,y] array
exports.apply2DTransform = function(transform) {
    return function() {
        var args = arguments;
        if(args.length === 3) {
            args = args[0];
        } // from map
        var xy = arguments.length === 1 ? args[0] : [args[0], args[1]];
        return exports.dot(transform, [xy[0], xy[1], 1]).slice(0, 2);
    };
};

// applies a 2D transformation matrix to an [x1,y1,x2,y2] array (to transform a segment)
exports.apply2DTransform2 = function(transform) {
    var at = exports.apply2DTransform(transform);
    return function(xys) {
        return at(xys.slice(0, 2)).concat(at(xys.slice(2, 4)));
    };
};

// converts a 2x3 css transform matrix, represented as a length 6 array, to a 3x3 matrix.
exports.convertCssMatrix = function(m) {
    if(m.length !== 6) {
        throw new Error('Css transform matrix not of length 6');
    }

    return [
        [m[0], m[2], m[4]],
        [m[1], m[3], m[5]],
        [0, 0, 1]
    ];
};

// find the inverse for a 3x3 affine transform matrix
exports.inverseTransformMatrix = function(m) {
    var out = [];
    mat3X3.invert(out, [
        m[0][0], m[0][1], m[0][2],
        m[1][0], m[1][1], m[1][2],
        m[2][0], m[2][1], m[2][2]
    ]);
    mat3X3.transpose(out, out);
    return [
        [out[0], out[1], out[2]],
        [out[3], out[4], out[5]],
        [out[6], out[7], out[8]]
    ];
};
<commit_msg>bypass and return default matrix if encountered a problem instead of throwing an error<commit_after>/**
* Copyright 2012-2020, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var mat3X3 = require('gl-mat3');

exports.init2dArray = function(rowLength, colLength) {
    var array = new Array(rowLength);
    for(var i = 0; i < rowLength; i++) array[i] = new Array(colLength);
    return array;
};

/**
 * transpose a (possibly ragged) 2d array z. inspired by
 * http://stackoverflow.com/questions/17428587/
 * transposing-a-2d-array-in-javascript
 */
exports.transposeRagged = function(z) {
    var maxlen = 0;
    var zlen = z.length;
    var i, j;
    // Maximum row length:
    for(i = 0; i < zlen; i++) maxlen = Math.max(maxlen, z[i].length);

    var t = new Array(maxlen);
    for(i = 0; i < maxlen; i++) {
        t[i] = new Array(zlen);
        for(j = 0; j < zlen; j++) t[i][j] = z[j][i];
    }

    return t;
};

// our own dot function so that we don't need to include numeric
exports.dot = function(x, y) {
    if(!(x.length && y.length) || x.length !== y.length) return null;

    var len = x.length;
    var out;
    var i;

    if(x[0].length) {
        // mat-vec or mat-mat
        out = new Array(len);
        for(i = 0; i < len; i++) out[i] = exports.dot(x[i], y);
    } else if(y[0].length) {
        // vec-mat
        var yTranspose = exports.transposeRagged(y);
        out = new Array(yTranspose.length);
        for(i = 0; i < yTranspose.length; i++) out[i] = exports.dot(x, yTranspose[i]);
    } else {
        // vec-vec
        out = 0;
        for(i = 0; i < len; i++) out += x[i] * y[i];
    }

    return out;
};

// translate by (x,y)
exports.translationMatrix = function(x, y) {
    return [[1, 0, x], [0, 1, y], [0, 0, 1]];
};

// rotate by alpha around (0,0)
exports.rotationMatrix = function(alpha) {
    var a = alpha * Math.PI / 180;
    return [[Math.cos(a), -Math.sin(a), 0],
            [Math.sin(a), Math.cos(a), 0],
            [0, 0, 1]];
};

// rotate by alpha around (x,y)
exports.rotationXYMatrix = function(a, x, y) {
    return exports.dot(
        exports.dot(exports.translationMatrix(x, y),
                    exports.rotationMatrix(a)),
        exports.translationMatrix(-x, -y));
};

// applies a 2D transformation matrix to either x and y params or an [x,y] array
exports.apply2DTransform = function(transform) {
    return function() {
        var args = arguments;
        if(args.length === 3) {
            args = args[0];
        } // from map
        var xy = arguments.length === 1 ? args[0] : [args[0], args[1]];
        return exports.dot(transform, [xy[0], xy[1], 1]).slice(0, 2);
    };
};

// applies a 2D transformation matrix to an [x1,y1,x2,y2] array (to transform a segment)
exports.apply2DTransform2 = function(transform) {
    var at = exports.apply2DTransform(transform);
    return function(xys) {
        return at(xys.slice(0, 2)).concat(at(xys.slice(2, 4)));
    };
};

// converts a 2x3 css transform matrix, represented as a length 6 array, to a 3x3 matrix.
exports.convertCssMatrix = function(m) {
    if(!m || m.length !== 6) {
        return [
            [1, 0, 0],
            [0, 1, 0],
            [0, 0, 1]
        ];
    }

    return [
        [m[0], m[2], m[4]],
        [m[1], m[3], m[5]],
        [0, 0, 1]
    ];
};

// find the inverse for a 3x3 affine transform matrix
exports.inverseTransformMatrix = function(m) {
    var out = [];
    mat3X3.invert(out, [
        m[0][0], m[0][1], m[0][2],
        m[1][0], m[1][1], m[1][2],
        m[2][0], m[2][1], m[2][2]
    ]);
    mat3X3.transpose(out, out);
    return [
        [out[0], out[1], out[2]],
        [out[3], out[4], out[5]],
        [out[6], out[7], out[8]]
    ];
};
<|endoftext|>