<commit_before>/**
 * Copyright 2016 IBM All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an 'AS IS' BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

var tape = require('tape');
var _test = require('tape-promise');
var test = _test(tape);

var hfc = require('hfc');
var util = require('util');
var fs = require('fs');
var testUtil = require('./util.js');

var Orderer = require('hfc/lib/Orderer.js');
var Chain = require('hfc/lib/Chain.js');

var keyValStorePath = testUtil.KVS;

var client = new hfc();
client.setStateStore(hfc.newDefaultKeyValueStore({
	path: testUtil.KVS
}));

//
// Orderer via chain setOrderer/getOrderer
//
// Set the orderer URL through the chain setOrderer method. Verify that the
// orderer URL was set correctly through the getOrderer method. Repeat the
// process by updating the orderer URL to a different address.
//
test('\n\n** TEST ** orderer via chain setOrderer/getOrderer', function(t) {
	//
	// Create and configure the test chain
	//
	var chain = client.newChain('testChain-orderer-member');
	try {
		var orderer = new Orderer('grpc://localhost:7050');
		chain.addOrderer(orderer);
		t.pass('Successfully set the new orderer URL');

		var orderers = chain.getOrderers();
		if(orderers !== null && orderers.length > 0 && orderers[0].getUrl() === 'grpc://localhost:7050') {
			t.pass('Successfully retrieved the new orderer URL from the chain');
		}
		else {
			t.fail('Failed to retieve the new orderer URL from the chain');
			t.end();
		}

		try {
			var orderer2 = new Orderer('grpc://localhost:5152');
			chain.addOrderer(orderer2);
			t.pass('Successfully updated the orderer URL');

			var orderers = chain.getOrderers();
			if(orderers !== null && orderers.length > 0 && orderers[1].getUrl() === 'grpc://localhost:5152') {
				t.pass('Successfully retrieved the upated orderer URL from the chain');
				t.end();
			}
			else {
				t.fail('Failed to retieve the updated orderer URL from the chain');
				t.end();
			}
		}
		catch(err2) {
			t.fail('Failed to update the order URL ' + err2);
			t.end();
		}
	}
	catch(err) {
		t.fail('Failed to set the new order URL ' + err);
		t.end();
	}
});

//
// Orderer via chain set/get bad address
//
// Set the orderer URL to a bad address through the chain setOrderer method.
// Verify that an error is reported when trying to set a bad address.
//
test('\n\n** TEST ** orderer via chain set/get bad address', function(t) {
	//
	// Create and configure the test chain
	//
	var chain = client.newChain('testChain-orderer-member1');

	t.throws(
		function() {
			var order_address = 'xxx';
			chain.addOrderer(new Orderer(order_address));
		},
		/InvalidProtocol: Invalid protocol: undefined/,
		'Test setting a bad orderer address'
	);

	t.throws(
		function() {
			chain.addOrderer(new Orderer());
		},
		/TypeError: Parameter 'url' must be a string/,
		'Test setting an empty orderer address'
	);

	t.end();
});

//
// Orderer via member missing orderer
//
// Attempt to send a request to the orderer with the sendTransaction method
// before the orderer URL was set. Verify that an error is reported when tying
// to send the request.
//
test('\n\n** TEST ** orderer via member missing orderer', function(t) {
	//
	// Create and configure the test chain
	//
	var chain = client.newChain('testChain-orderer-member2');

	testUtil.getSubmitter(client, t)
	.then(
		function(admin) {
			t.pass('Successfully enrolled user \'admin\'');

			// send to orderer
			return chain.sendTransaction('data');
		},
		function(err) {
			t.fail('Failed to enroll user \'admin\'. ' + err);
			t.end();
		}
	).then(
		function(status) {
			console.log('Status: ' + status + ', type: (' + typeof status + ')');
			if (status === 0) {
				t.fail('Successfully submitted request, which is bad because the chain is missing orderers.');
			} else {
				t.pass('Successfully tested invalid submission due to missing orderers. Error code: ' + status);
			}

			t.end();
		},
		function(err) {
			console.log('Error: ' + err);
			t.pass('Successfully tested invalid submission due to missing orderers. Error code: ' + err);
			t.end();
		}
	).catch(function(err) {
		t.fail('Failed request. ' + err);
		t.end();
	});
});

//
// Orderer via member null data
//
// Attempt to send a request to the orderer with the sendTransaction method
// with the data set to null. Verify that an error is reported when tying
// to send null data.
//
test('\n\n** TEST ** orderer via member null data', function(t) {
	//
	// Create and configure the test chain
	//
	var chain = client.newChain('testChain-orderer-member3');

	chain.addOrderer(new Orderer('grpc://localhost:7050'));

	testUtil.getSubmitter(client, t)
	.then(
		function(admin) {
			t.pass('Successfully enrolled user \'admin\'');

			// send to orderer
			return chain.sendTransaction(null);
		},
		function(err) {
			t.fail('Failed to enroll user \'admin\'. ' + err);
			t.end();
		}
	).then(
		function(status) {
			if (status === 0) {
				t.fail('Successfully submitted request, which is bad because the submission was missing data');
				t.end();
			} else {
				t.pass('Successfully tested invalid submission due to null data. Error code: ' + status);

				return chain.sendTransaction('some non-null but still bad data');
			}
		},
		function(err) {
			t.pass('Failed to submit. Error code: ' + err);
			t.end();
		}
	).then(
		function(status) {
			if (status === 0) {
				t.fail('Successfully submitted request, which is bad because the submission was using bad data');
				t.end();
			} else {
				t.pass('Successfully tested invalid submission due to bad data. Error code: ' + status);
				t.end();
			}
		},
		function(err) {
			t.pass('Failed to submit. Error code: ' + err);
			t.end();
		}
	).catch(function(err) {
		t.pass('Failed request. ' + err);
		t.end();
	});
});

//
// Orderer via member bad orderer address
//
// Attempt to send a request to the orderer with the sendTransaction method
// with the orderer address set to a bad URL. Verify that an error is reported
// when tying to send the request.
//
test('\n\n** TEST ** orderer via member bad orderer address', function(t) {
	//
	// Create and configure the test chain
	//
	var chain = client.newChain('testChain-orderer-member4');

	// Set bad orderer address here
	chain.addOrderer(new Orderer('grpc://localhost:5199'));

	testUtil.getSubmitter(client, t)
	.then(
		function(admin) {
			t.pass('Successfully enrolled user \'admin\'');

			// send to orderer
			return chain.sendTransaction('some data');
		},
		function(err) {
			t.fail('Failed to enroll user \'admin\'. ' + err);
			t.end();
		}
	).then(
		function(status) {
			console.log('Status: ' + status + ', type: (' + typeof status + ')');
			if (status === 0) {
				t.fail('Successfully submitted request, which is bad because the chain\'s orderer address is invalid');
			} else {
				t.pass('Successfully tested invalid submission due to the chain using orderers with bad addresses. Error code: ' + status);
			}
			t.end();
		},
		function(err) {
			t.pass('Failed to submit ::' + err);
			t.end();
		}
	).catch(function(err) {
		t.pass('Failed to submit orderer request. ' + err);
		t.end();
	});
});
<commit_msg>Fix error messages in orderer-chain-tests.js<commit_after>/**
 * Copyright 2016 IBM All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an 'AS IS' BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

var tape = require('tape');
var _test = require('tape-promise');
var test = _test(tape);

var hfc = require('hfc');
var util = require('util');
var fs = require('fs');
var testUtil = require('./util.js');

var Orderer = require('hfc/lib/Orderer.js');
var Chain = require('hfc/lib/Chain.js');

var keyValStorePath = testUtil.KVS;

var client = new hfc();
client.setStateStore(hfc.newDefaultKeyValueStore({
	path: testUtil.KVS
}));

//
// Orderer via chain setOrderer/getOrderer
//
// Set the orderer URL through the chain setOrderer method. Verify that the
// orderer URL was set correctly through the getOrderer method. Repeat the
// process by updating the orderer URL to a different address.
//
test('\n\n** TEST ** orderer via chain setOrderer/getOrderer', function(t) {
	//
	// Create and configure the test chain
	//
	var chain = client.newChain('testChain-orderer-member');
	try {
		var orderer = new Orderer('grpc://localhost:7050');
		chain.addOrderer(orderer);
		t.pass('Successfully set the new orderer URL');

		var orderers = chain.getOrderers();
		if(orderers !== null && orderers.length > 0 && orderers[0].getUrl() === 'grpc://localhost:7050') {
			t.pass('Successfully retrieved the new orderer URL from the chain');
		}
		else {
			t.fail('Failed to retieve the new orderer URL from the chain');
			t.end();
		}

		try {
			var orderer2 = new Orderer('grpc://localhost:5152');
			chain.addOrderer(orderer2);
			t.pass('Successfully updated the orderer URL');

			var orderers = chain.getOrderers();
			if(orderers !== null && orderers.length > 0 && orderers[1].getUrl() === 'grpc://localhost:5152') {
				t.pass('Successfully retrieved the upated orderer URL from the chain');
				t.end();
			}
			else {
				t.fail('Failed to retieve the updated orderer URL from the chain');
				t.end();
			}
		}
		catch(err2) {
			t.fail('Failed to update the order URL ' + err2);
			t.end();
		}
	}
	catch(err) {
		t.fail('Failed to set the new order URL ' + err);
		t.end();
	}
});

//
// Orderer via chain set/get bad address
//
// Set the orderer URL to a bad address through the chain setOrderer method.
// Verify that an error is reported when trying to set a bad address.
//
test('\n\n** TEST ** orderer via chain set/get bad address', function(t) {
	//
	// Create and configure the test chain
	//
	var chain = client.newChain('testChain-orderer-member1');

	t.throws(
		function() {
			var order_address = 'xxx';
			chain.addOrderer(new Orderer(order_address));
		},
		/InvalidProtocol: Invalid protocol: undefined/,
		'Test setting a bad orderer address'
	);

	t.throws(
		function() {
			chain.addOrderer(new Orderer());
		},
		/TypeError: Parameter "url" must be a string, not undefined/,
		'Test setting an empty orderer address'
	);

	t.end();
});

//
// Orderer via member missing orderer
//
// Attempt to send a request to the orderer with the sendTransaction method
// before the orderer URL was set. Verify that an error is reported when tying
// to send the request.
//
test('\n\n** TEST ** orderer via member missing orderer', function(t) {
	//
	// Create and configure the test chain
	//
	var chain = client.newChain('testChain-orderer-member2');

	testUtil.getSubmitter(client, t)
	.then(
		function(admin) {
			t.pass('Successfully enrolled user \'admin\'');

			// send to orderer
			return chain.sendTransaction('data');
		},
		function(err) {
			t.fail('Failed to enroll user \'admin\'. ' + err);
			t.end();
		}
	).then(
		function(status) {
			console.log('Status: ' + status + ', type: (' + typeof status + ')');
			if (status === 0) {
				t.fail('Successfully submitted request, which is bad because the chain is missing orderers.');
			} else {
				t.pass('Successfully tested invalid submission due to missing orderers. Error code: ' + status);
			}

			t.end();
		},
		function(err) {
			console.log('Error: ' + err);
			t.pass('Successfully tested invalid submission due to missing orderers. Error code: ' + err);
			t.end();
		}
	).catch(function(err) {
		t.fail('Failed request. ' + err);
		t.end();
	});
});

//
// Orderer via member null data
//
// Attempt to send a request to the orderer with the sendTransaction method
// with the data set to null. Verify that an error is reported when tying
// to send null data.
//
test('\n\n** TEST ** orderer via member null data', function(t) {
	//
	// Create and configure the test chain
	//
	var chain = client.newChain('testChain-orderer-member3');

	chain.addOrderer(new Orderer('grpc://localhost:7050'));

	testUtil.getSubmitter(client, t)
	.then(
		function(admin) {
			t.pass('Successfully enrolled user \'admin\'');

			// send to orderer
			return chain.sendTransaction(null);
		},
		function(err) {
			t.fail('Failed to enroll user \'admin\'. ' + err);
			t.end();
		}
	).then(
		function(status) {
			if (status === 0) {
				t.fail('Successfully submitted request, which is bad because the submission was missing data');
				t.end();
			} else {
				t.pass('Successfully tested invalid submission due to null data. Error code: ' + status);

				return chain.sendTransaction('some non-null but still bad data');
			}
		},
		function(err) {
			t.pass('Failed to submit. Error code: ' + err);
			t.end();
		}
	).then(
		function(status) {
			if (status === 0) {
				t.fail('Successfully submitted request, which is bad because the submission was using bad data');
				t.end();
			} else {
				t.pass('Successfully tested invalid submission due to bad data. Error code: ' + status);
				t.end();
			}
		},
		function(err) {
			t.pass('Failed to submit. Error code: ' + err);
			t.end();
		}
	).catch(function(err) {
		t.pass('Failed request. ' + err);
		t.end();
	});
});

//
// Orderer via member bad orderer address
//
// Attempt to send a request to the orderer with the sendTransaction method
// with the orderer address set to a bad URL. Verify that an error is reported
// when tying to send the request.
//
test('\n\n** TEST ** orderer via member bad orderer address', function(t) {
	//
	// Create and configure the test chain
	//
	var chain = client.newChain('testChain-orderer-member4');

	// Set bad orderer address here
	chain.addOrderer(new Orderer('grpc://localhost:5199'));

	testUtil.getSubmitter(client, t)
	.then(
		function(admin) {
			t.pass('Successfully enrolled user \'admin\'');

			// send to orderer
			return chain.sendTransaction('some data');
		},
		function(err) {
			t.fail('Failed to enroll user \'admin\'. ' + err);
			t.end();
		}
	).then(
		function(status) {
			console.log('Status: ' + status + ', type: (' + typeof status + ')');
			if (status === 0) {
				t.fail('Successfully submitted request, which is bad because the chain\'s orderer address is invalid');
			} else {
				t.pass('Successfully tested invalid submission due to the chain using orderers with bad addresses. Error code: ' + status);
			}
			t.end();
		},
		function(err) {
			t.pass('Failed to submit ::' + err);
			t.end();
		}
	).catch(function(err) {
		t.pass('Failed to submit orderer request. ' + err);
		t.end();
	});
});
<|endoftext|>


<commit_before>import path from 'path'
import Mocha from 'mocha'

import { runInFiberContext, wrapCommand, runHook } from 'wdio-sync'

const INTERFACES = {
    bdd: ['before', 'beforeEach', 'it', 'after', 'afterEach'],
    tdd: ['suiteSetup', 'setup', 'test', 'suiteTeardown', 'teardown']
}

const EVENTS = {
    'suite': 'suite:start',
    'suite end': 'suite:end',
    'test': 'test:start',
    'test end': 'test:end',
    'hook': 'hook:start',
    'hook end': 'hook:end',
    'pass': 'test:pass',
    'fail': 'test:fail',
    'pending': 'test:pending'
}

const DONOTHING = function () {}

/**
 * mimik globals to rewire it out in tests
 */
const require = require
const process = process

let adapter = {}

/**
 * Mocha runner
 */
adapter.run = async function mochaAdapter (cid, config = { mochaOpts: {} }, specs = [], capabilities) {
    let compilers = config.mochaOpts.compilers
    let requires = config.mochaOpts.require
    let runner

    if (typeof config.mochaOpts.ui !== 'string' || !config.mochaOpts.ui.match(/(bdd|tdd)/i)) {
        config.mochaOpts.ui = 'bdd'
    }

    const mocha = new Mocha(config.mochaOpts)
    mocha.loadFiles()
    mocha.reporter(DONOTHING)

    adapter.requireExternalModules(compilers, requires)

    wrapCommand(global.browser)

    specs.forEach((spec) => mocha.addFile(spec))
    mocha.suite.on('pre-require', () => INTERFACES[config.mochaOpts.ui].forEach(runInFiberContext.bind(null, INTERFACES, config.mochaOpts.ui)))

    await runHook(config.before)
    let result = await new Promise((resolve, reject) => {
        runner = mocha.run(resolve)
        Object.keys(EVENTS).forEach((e) => runner.on(e, adapter.emit.bind(null, EVENTS[e], cid, capabilities)))
    })
    await runHook(config.after)
    return result
}

adapter.requireExternalModules = function (compilers = [], requires = []) {
    compilers.concat(requires).forEach((mod) => {
        mod = mod.split(':')
        mod = mod[mod.length - 1]

        if (mod[0] === '.') {
            mod = path.join(process.cwd(), mod)
        }

        require(mod)
    })
}

adapter.emit = function (event, cid, capabilities, payload, err) {
    if (err) {
        err = {
            message: err.message,
            stack: err.stack
        }
    }

    let message = {
        event,
        cid,
        err,
        title: payload.title,
        pending: payload.pending || false,
        parent: payload.parent ? payload.parent.title : null,
        type: payload.tests ? 'suite' : 'test',
        file: payload.file,
        duration: payload.duration,
        runner: {}
    }

    message.runner[cid] = capabilities
    process.send(message)
}

export default adapter
<commit_msg>Not yet working<commit_after>import path from 'path'
import Mocha from 'mocha'

import { runInFiberContext, wrapCommand, runHook } from 'wdio-sync'

const INTERFACES = {
    bdd: ['before', 'beforeEach', 'it', 'after', 'afterEach'],
    tdd: ['suiteSetup', 'setup', 'test', 'suiteTeardown', 'teardown']
}

const EVENTS = {
    'suite': 'suite:start',
    'suite end': 'suite:end',
    'test': 'test:start',
    'test end': 'test:end',
    'hook': 'hook:start',
    'hook end': 'hook:end',
    'pass': 'test:pass',
    'fail': 'test:fail',
    'pending': 'test:pending'
}

const DONOTHING = function () {}

/**
 * mimik globals to rewire it out in tests
 */
const require = require
const process = process

let adapter = {}

/**
 * Mocha runner
 */
adapter.run = async function mochaAdapter (cid, config = { mochaOpts: {} }, specs = [], capabilities) {
    let compilers = config.mochaOpts.compilers
    let requires = config.mochaOpts.require
    let runner

    if (typeof config.mochaOpts.ui !== 'string' || !config.mochaOpts.ui.match(/(bdd|tdd)/i)) {
        config.mochaOpts.ui = 'bdd'
    }

    const mocha = new Mocha(config.mochaOpts)
    mocha.loadFiles()
    mocha.reporter(DONOTHING)

    adapter.requireExternalModules(compilers, requires)

    wrapCommand(global.browser)

    specs.forEach((spec) => mocha.addFile(spec))
    mocha.suite.on('pre-require', () => INTERFACES[config.mochaOpts.ui].forEach(runInFiberContext.bind(null, INTERFACES, config.mochaOpts.ui)))

    await runHook(config.before)
    let result = await new Promise((resolve, reject) => {
        runner = mocha.run(resolve)
        Object.keys(EVENTS).forEach((e) => runner.on(e, adapter.emit.bind(null, EVENTS[e], cid, capabilities)))

        runner.suite.afterEach(adapter.afterEach.call(runner, config))
    })
    await runHook(config.after)
    return result
}

adapter.afterEach = function(config) {

    return function() {
        const results = {
            title: this.currentTest.title,
            file: this.currentTest.file,
            passed: (this.currentTest.state === 'passed')
        };

        runHook(config.afterTest.bind(null, results));
    }
}

adapter.requireExternalModules = function (compilers = [], requires = []) {
    compilers.concat(requires).forEach((mod) => {
        mod = mod.split(':')
        mod = mod[mod.length - 1]

        if (mod[0] === '.') {
            mod = path.join(process.cwd(), mod)
        }

        require(mod)
    })
}

adapter.emit = function (event, cid, capabilities, payload, err) {
    if (err) {
        err = {
            message: err.message,
            stack: err.stack
        }
    }

    let message = {
        event,
        cid,
        err,
        title: payload.title,
        pending: payload.pending || false,
        parent: payload.parent ? payload.parent.title : null,
        type: payload.tests ? 'suite' : 'test',
        file: payload.file,
        duration: payload.duration,
        runner: {}
    }

    message.runner[cid] = capabilities
    process.send(message)
}

export default adapter
<|endoftext|>


<commit_before>describe('AdminRadioAction', function(){
  var c = window.c, m = window.m, models = window.c.models,
      AdminRadioAction = c.AdminRadioAction,
      testModel = m.postgrest.model('test'),
      item = {
        getKey: 1,
        updateKey: 1,
        testKey: 'foo',
        reward: {
          id: 1,
          description: 'description'
        }
      },
      error = false,
      testStr = 'updated',
      fakeData = {},
      ctrl, $output;
  var response = [
    function(callback, err){
      callback([fakeData]);
    }
  ];

  var args = {
        getKey: 'testKey',
        updateKey: 'updateKey',
        property: 'test',
        radios: 'rewards',
        callToAction: 'cta',
        outerLabel: 'outer',
        getModel: testModel,
        updateModel: testModel
      };

  describe('controller', function(){
    beforeAll(function(){
      spyOn(testModel, 'patchOptions');
      spyOn(testModel, 'getPageOptions');
      spyOn(m, 'redraw');
      ctrl = AdminRadioAction.controller({data: args, item: item});
      spyOn(ctrl.setLoader, 'load').and.returnValue({
        then: function(callback, err){
          item.updateKey = testStr;
          callback(item);
        }
      });
    });

    it('should return a function called complete', function(){
      expect(ctrl.complete).toBeFunction();
    });
    it('should return a function called description', function(){
      expect(ctrl.description).toBeFunction();
    });
    it('should return a function called setDescription', function(){
      expect(ctrl.setDescription).toBeFunction();
    });
    it('should return a function called error', function(){
      expect(ctrl.error).toBeFunction();
    });
    it('should return a function called setLoader', function(){
      expect(ctrl.setLoader).toBeFunction();
    });
    it('should return a function called getLoader', function(){
      expect(ctrl.getLoader).toBeFunction();
    });
    it('should return a function called newValue', function(){
      expect(ctrl.newValue).toBeFunction();
    });
    it('should return a function called submit', function(){
      expect(ctrl.submit).toBeFunction();
    });
    it('should return a function called submit', function(){
      expect(ctrl.submit).toBeFunction();
    });
    it('should return a function called toggler', function(){
      expect(ctrl.toggler).toBeFunction();
    });
    it('should return a function called unload', function(){
      expect(ctrl.unload).toBeFunction();
    });
    it('should return a function called unload', function(){
      expect(ctrl.radios).toBeFunction();
    });
    it('should instantiate a get loader with filter set', function(){
      var filterSample = {};
      filterSample[args.getKey] = 'eq.' + item.testKey;
      expect(testModel.getPageOptions).toHaveBeenCalledWith(filterSample);
    });
    it('should instantiate a set loader with filter set', function(){
      var filterSample = {};
      filterSample[args.updateKey] = 'eq.' + item.updateKey;
      expect(testModel.patchOptions).toHaveBeenCalledWith(filterSample, {});
    });
    it('should set complete to true and updateItem on submit', function(){
      ctrl.newValue(testStr);
      ctrl.submit();
      expect(ctrl.setLoader.load).toHaveBeenCalled();
      expect(ctrl.complete()).toBeTrue();
      expect(item.updateKey).toEqual(testStr);
    });
    it('should set a new description and call redraw on setDescription', function(){
      var desc = testStr;
      ctrl.setDescription(desc);
      expect(ctrl.description()).toEqual(testStr);
      expect(m.redraw).toHaveBeenCalled();
    });
  });
  describe('view', function(){
    beforeAll(function(){
      ctrl = AdminRadioAction.controller({data: args, item: item});
      fakeData[args.radios] = [
        {
          id: 1,
          description: 'description_1',
          minimum_value: 10
        },
        {
          id: 2,
          description: 'description_2',
          minimum_value: 20
        }
      ];
      spyOn(m, 'request').and.returnValue({
        then: response[0]
      });
      $output = mq(AdminRadioAction, {data: args, item: item});

    });

    it('shoud only render the outerLabel on first render', function(){
      expect($output.contains(args.outerLabel)).toBeTrue();
      expect($output.contains(args.callToAction)).toBeFalse();
    });

    describe('on action button click', function(){
      beforeAll(function(){
        $output.click('button');
      });

      it('should render a row of radio inputs', function(){
        expect($output.find('input[type="radio"]').length).toEqual(fakeData[args.radios].length);
      });
      it('should render the description of the default selected radio', function(){
        expect($output.contains(item.reward.description)).toBeTrue();
      });
      it('should send an patch request on form submit', function(){
        $output.click('#r-1');
        $output.trigger('form', 'submit');
        //One request to get another one to set
        expect(m.request.calls.count()).toEqual(2);
      });
    });
  });
});
<commit_msg>Fixes specs<commit_after>describe('AdminRadioAction', function(){
  var c = window.c, m = window.m, models = window.c.models,
      AdminRadioAction = c.AdminRadioAction,
      testModel = m.postgrest.model('test'),
      item = {
        getKey: 1,
        updateKey: 1,
        testKey: 'foo',
        reward: {
          id: 1,
          description: 'description'
        }
      },
      error = false,
      testStr = 'updated',
      fakeData = {},
      ctrl, $output;
  var response = function(callback, err){
    callback(fakeData);
  };

  var args = {
        getKey: 'testKey',
        updateKey: 'updateKey',
        property: 'test',
        radios: 'rewards',
        callToAction: 'cta',
        outerLabel: 'outer',
        getModel: testModel,
        updateModel: testModel
      };

  describe('controller', function(){
    beforeAll(function(){
      spyOn(testModel, 'patchOptions');
      spyOn(testModel, 'getPageOptions');
      spyOn(m, 'redraw');
      ctrl = AdminRadioAction.controller({data: args, item: item});
      spyOn(ctrl.setLoader, 'load').and.returnValue({
        then: function(callback, err){
          item.updateKey = testStr;
          callback(item);
        }
      });
    });

    it('should return a function called complete', function(){
      expect(ctrl.complete).toBeFunction();
    });
    it('should return a function called description', function(){
      expect(ctrl.description).toBeFunction();
    });
    it('should return a function called setDescription', function(){
      expect(ctrl.setDescription).toBeFunction();
    });
    it('should return a function called error', function(){
      expect(ctrl.error).toBeFunction();
    });
    it('should return a function called setLoader', function(){
      expect(ctrl.setLoader).toBeFunction();
    });
    it('should return a function called getLoader', function(){
      expect(ctrl.getLoader).toBeFunction();
    });
    it('should return a function called newValue', function(){
      expect(ctrl.newValue).toBeFunction();
    });
    it('should return a function called submit', function(){
      expect(ctrl.submit).toBeFunction();
    });
    it('should return a function called submit', function(){
      expect(ctrl.submit).toBeFunction();
    });
    it('should return a function called toggler', function(){
      expect(ctrl.toggler).toBeFunction();
    });
    it('should return a function called unload', function(){
      expect(ctrl.unload).toBeFunction();
    });
    it('should return a function called unload', function(){
      expect(ctrl.radios).toBeFunction();
    });
    it('should instantiate a get loader with filter set', function(){
      var filterSample = {};
      filterSample[args.getKey] = 'eq.' + item.testKey;
      expect(testModel.getPageOptions).toHaveBeenCalledWith(filterSample);
    });
    it('should instantiate a set loader with filter set', function(){
      var filterSample = {};
      filterSample[args.updateKey] = 'eq.' + item.updateKey;
      expect(testModel.patchOptions).toHaveBeenCalledWith(filterSample, {});
    });
    it('should set complete to true and updateItem on submit', function(){
      ctrl.newValue(testStr);
      ctrl.submit();
      expect(ctrl.setLoader.load).toHaveBeenCalled();
      expect(ctrl.complete()).toBeTrue();
      expect(item.updateKey).toEqual(testStr);
    });
    it('should set a new description and call redraw on setDescription', function(){
      var desc = testStr;
      ctrl.setDescription(desc);
      expect(ctrl.description()).toEqual(testStr);
      expect(m.redraw).toHaveBeenCalled();
    });
  });
  describe('view', function(){
    beforeAll(function(){
      ctrl = AdminRadioAction.controller({data: args, item: item});
      fakeData = [
        {
          id: 1,
          description: 'description_1',
          minimum_value: 10
        },
        {
          id: 2,
          description: 'description_2',
          minimum_value: 20
        }
      ];
      spyOn(m, 'request').and.returnValue({
        then: response
      });
      $output = mq(AdminRadioAction, {data: args, item: item});

    });

    it('shoud only render the outerLabel on first render', function(){
      expect($output.contains(args.outerLabel)).toBeTrue();
      expect($output.contains(args.callToAction)).toBeFalse();
    });

    describe('on action button click', function(){
      beforeAll(function(){
        $output.click('button');
      });

      it('should render a row of radio inputs', function(){
        expect($output.find('input[type="radio"]').length).toEqual(fakeData.length);
      });
      it('should render the description of the default selected radio', function(){
        expect($output.contains(item.reward.description)).toBeTrue();
      });
      it('should send an patch request on form submit', function(){
        $output.click('#r-1');
        $output.trigger('form', 'submit');
        //One request to get another one to set
        expect(m.request.calls.count()).toEqual(2);
      });
    });
  });
});
<|endoftext|>


<commit_before>/**
 * -------------------------- Módulo PlayFile --------------------------------------------------
 * @author Diego Alberto Molina Vera
 *
 * Encargada de reproducir la canción, tocar la siguiente canción o la anterior.
 * Acá se usa la Audio Web API para reproducir la canción y también usar datos
 * obtenidos mediante el buffer. También la API nos permite manipular el archivo de audio
 */
/* --------------------------------------- Módulos ------------------------------------------- */
const { dialog } = require('electron').remote;
const path = require('path');
require('./commons');

/* --------------------------------------- Variables ------------------------------------------- */
let isMovingForward = false; // Si se está tratando de adelantar la cación a un tiempo determinado
let isSongPlaying = false; // Se ejecutó play sobre el AudioNode
let isNexAble = false; // Se puede reproducir la siguiente canción
let isPrevExec = false; // Solo se agregan las canciones ya reproducidas cuando se presiona next
let position = null; // Posición de la canción actual
let tmpPosition = []; // Posición de la canción anteriormente reproducida
let filePath = ''; // Ruta de la canción
let songs = {}; // Listado de canciones
let notification = null; // Despliega una notificación de la canción que se va a reproducir

// Variables necesarias para trabajar sobre el AudioContext
const audioContext = new window.AudioContext(); // Objeto AudioContext
const xhtr = new XMLHttpRequest(); // Objeto XMLHttpRequest
// const panner = audioContext.createPanner();
//   panner.panningModel = 'HRTF';
//   panner.distanceModel = 'exponential';
//   panner.coneOuterGain = 1;
//   panner.orientationZ = 1.6;
//   panner.positionZ = 1.6;
//   panner.positionX = 1;
//   panner.positionY = 1;
//   panner.refDistance = 2;
// Frecuencias
const hrz = [
 40, 80, 90, 100, 120, 150, 200,
 300, 400, 500, 600, 800, 1000,
 1600, 2000, 3000, 4000, 5000, 6000,
 7000, 8000, 10000, 16000
];

let filter = []; // Array con el filtro a usar en distintas frecuencias
let _duration = 0; // Duración máxima de la canción
let _buffer = {}; // Buffer devuelto por decodeAudioData
let source = {}; // Objeto AudioNode

// Variables para generar el calculo del tiempo transcurrido
let millisecond = 1;
let interval = null; // Función interval para crear el tiempo de reproducción
let _minute = 0; // Final
let _second = 0; // Final
let forward = 0; // tiempo estimado dónde debería de seguir corriendo la canción al adelantarla
let percent = 0;
let minute = 0; // Inicial
let second = 0; // Inicial
let lapse = 0;
let time = 0; // Tiempo total final

/** --------------------------------------- Funciones --------------------------------------- **/
// Recibe el listado de canciones desde el archivo listSongs.js
function setSongs(_songs) {
  songs = _songs;
  filters();
}

// Retorna un número aleatorio entre 0 y el total de canciones
function shuffle() { return Math.floor(Math.random() * songs.length).toString(); }

// Reproduce una cancion o la pausará
// Responde a todos los posibles estados de una canción
function playSong() {
  if (!isSongPlaying && audioContext.state === 'running') { // Primera vez
    dataSong(shuffle());
    play();

    return 'resume';
  } else if (isSongPlaying && audioContext.state === 'running') { // Ya reproduciendo
    audioContext.suspend().then(() => {
      isSongPlaying = false;
      clearInterval(interval);
    });

    return 'paused';
  } else if (!isSongPlaying && audioContext.state === 'suspended') { // Pausado
    isSongPlaying = true;
    ++millisecond;
    startTimer();
    audioContext.resume();

    return 'resume';
  }
}

// Genera el tiempo que lleva reproduciendose la canción
function startTimer() {
  const iter = () => {
    ++millisecond;
    if (millisecond / 100 > second + (60 * minute)) { // Segundos
      if (second > 59) {
        ++minute;
        second = 0;
      }

      // Tiempo transcurrido
      $('#time-start').text(`${minute > 9 ? `${minute}` : `0${minute}`}${second > 9 ? `:${second}` : `:0${second}`}`);
      $('#progress-bar').css(`width:${percent += lapse}%`); // Barra de carga
      ++second;
    }
  }
  interval = setInterval(iter, 10);
}

// Limpi el tiempo transcurrido
function stopTimer() {
  if (!isMovingForward) {
    isSongPlaying = false;
    clearInterval(interval);
    $('#time-start').text('00:00');
    millisecond = 1;
    second = minute = percent =
    _duration = _minute = _second = time = 0;
    if (isNexAble && !isMovingForward) nextSong();
  } else if (isMovingForward) {
    /**
     * La función stop tarda unos milesegundos más que ejecutar la función moveForward.
     * Por lo tanto lo que continua después de detener la canción deberá ser ejecutado
     * dentro de la función onended
     */
    // Se debe crear un nuevo AudioNode, ya que al dar stop el nodo se elimina
    source = audioContext.createBufferSource();

    // Evento que se gatilla al terminar la canción
    source.onended = stopTimer;

    // Conectar todos los nodos
    source.buffer = _buffer;
    source
    .connect(filter[0]) // 40
    .connect(filter[1]) // 80
    .connect(filter[2]) // 90
    .connect(filter[3]) // 100
    .connect(filter[4]) // 120
    .connect(filter[5]) // 150
    .connect(filter[6]) // 200
    .connect(filter[7]) // 300
    .connect(filter[8]) // 400
    .connect(filter[9]) // 500
    .connect(filter[10]) // 600
    .connect(filter[11]) // 800
    .connect(filter[12]) // 1000
    .connect(filter[13]) // 1600
    .connect(filter[14]) // 2000
    .connect(filter[15]) // 3000
    .connect(filter[16]) // 4000
    .connect(filter[17]) // 5000
    .connect(filter[18]) // 6000
    .connect(filter[19]) // 7000
    .connect(filter[20]) // 8000
    .connect(filter[21]) // 10000
    .connect(filter[22]) // 16000
    // .connect(panner)
    .connect(audioContext.destination);
    startTimer();
    source.start(0, forward);
    isMovingForward = false;
    isSongPlaying = true;
  }
}

// Recibe la posición de la canción a buscar en el objeto song
// para desplegarlos en la interfaz
function dataSong(_position) {
  if (position !== null && !isPrevExec) tmpPosition.push(position);

  const infoSong = songs[(position = parseInt(_position, 10))];
  filePath = infoSong.filename; // Ruta donde se encuentra el archivo a reproducir

  // Título de la canción
  $('#song-title').data({position}).child().each(v => { v.text(infoSong.title); });
  // Artista
  $('#artist').child().each(v => { v.text(infoSong.artist); });
  // Album
  $('#album').child().each(v => { v.text(infoSong.album); });

  // Mostrar notificación
  if (notification !== null) notification.close();

  notification = null

  notification = new Notification(infoSong.title.replace(/\ /g, ' '), {
    lang: 'US',
    tag: 'song',
    body: `${infoSong.artist.replace(/\ /g, ' ')} from ${infoSong.album.replace(/\ /g, ' ')}`,
    icon: path.join(__dirname, '..', 'img', 'play.png')
  });
}

// EJecuta, por medio de la Audio Web API, la canción.
// Se obtiene un array buffer con info útil para usar
function play() {
  // Creamos un Buffer que contendrá la canción
  source = audioContext.createBufferSource();

  // Leer erl achivo de audio
  xhtr.open('GET', `file://${filePath}`, true);
  xhtr.responseType = 'arraybuffer';
  xhtr.onload = () => {
    audioContext.decodeAudioData(xhtr.response).then(buffer => {
      // Para ser usado al momento de querer adelantar la canción
      // El buffer nos entrega la duración de la canción.
      // La duración de la cación está en segundos, por ende hay que pasarla a minutos.
      _buffer = buffer;
      time = ((_duration = _buffer.duration) / 60).toString();
      _minute = parseInt(time.slice(0, time.lastIndexOf('.')), 10);
      _second = Math.floor(parseFloat(time.slice(time.lastIndexOf('.'))) * 60);
      lapse = 100 / _duration; // Porcentaje a usar por cada segundo en la barra de progreso
      $('#time-end').text(`${_minute > 9 ? `${_minute}` : `0${_minute}`}${_second > 9 ? `:${_second}` : `:0${_second}`}`);

      // Evento que se gatilla al terminar la canción
      source.onended = stopTimer;

      // Conectar todos los nodos
      source.buffer = _buffer;
      source.connect(filter[0]) // 40
      .connect(filter[1]) // 80
      .connect(filter[2]) // 90
      .connect(filter[3]) // 100
      .connect(filter[4]) // 120
      .connect(filter[5]) // 150
      .connect(filter[6]) // 200
      .connect(filter[7]) // 300
      .connect(filter[8]) // 400
      .connect(filter[9]) // 500
      .connect(filter[10]) // 600
      .connect(filter[11]) // 800
      .connect(filter[12]) // 1000
      .connect(filter[13]) // 1600
      .connect(filter[14]) // 2000
      .connect(filter[15]) // 3000
      .connect(filter[16]) // 4000
      .connect(filter[17]) // 5000
      .connect(filter[18]) // 6000
      .connect(filter[19]) // 7000
      .connect(filter[20]) // 8000
      .connect(filter[21]) // 10000
      .connect(filter[22]) // 16000
      // .connect(panner)
      .connect(audioContext.destination);

      // Inicializar el tiempo y la canción
      startTimer();
      source.start(0);
      isNexAble = isSongPlaying = true;
    }, reason => {
      dialog.showErrorBox('Error [002]', `${jread(LANG_FILE)[jread(CONFIG_FILE).lang].alerts.playSong}\n${reason}`);
      return;
    });
  };
  xhtr.send(null);
}

// Reproduce la siguiente canción.
// Esta función se comparte cuando se genera la lista de canciones,
// ya que al dar click sobre una canción, la que se reproduce es otra ("siguiente").
function nextSong(_position = -1) {
  isPrevExec = false;
  if (_position !== -1) {
    // ver si está reproduciendose o no
    if (isSongPlaying && audioContext.state === 'running' ||
      !isSongPlaying && audioContext.state === 'suspended') {
      if (!isSongPlaying && audioContext.state === 'suspended') audioContext.resume();

      isNexAble = false;
      source.stop(0);
      source = null;
    }
    dataSong(_position)
    play();
  } else {
    // Ver en primera instancia si es posible reproducir la siguiente canción.
    // Esto va a depender de si se ejecutó ya una canción.
    // Si no se válida, podrían reproducirse varias pistas a la vez - No queremos esto :-(
    if (isNexAble) {
      isNexAble = false;
      dataSong(jread(CONFIG_FILE).shuffle ? shuffle() : (songs.length - 1 > position ? position + 1 : 0));
      // si está sonando la canción, esta se debe detener para tocar la nueva
      if (isSongPlaying && audioContext.state === 'running' ||
         !isSongPlaying && audioContext.state === 'suspended') {
        // Verificar si el contexto está pausado o no.
        // Si está pausado no se reproducirá una nueva pista
        if (!isSongPlaying && audioContext.state === 'suspended') audioContext.resume();

        source.stop(0);
        source = null;
      }

      play();
    }
  }
}

// Reproducirá la canción anterior
function prevSong() {
  if (isNexAble && tmpPosition.length > 0) {
    isNexAble = false;
    isPrevExec = true;
    dataSong(tmpPosition.pop());

    // si está sonando la canción, esta se debe detener para tocar la nueva
    if (isSongPlaying && audioContext.state === 'running') {
      source.stop(0);
      source = null;
    }
    // Verificar si el contexto está pausado o no.
    // Si está pausado no se reproducirá una nueva pista
    if (!isSongPlaying && audioContext.state === 'suspended') audioContext.resume();
    play();
  }
}

// Cambia los valores en la frecuencia específica
function setFilterVal(a, b) {
  filter[a].gain.setValueAtTime(b, audioContext.currentTime);
}

// Crea y asigna BiquadFilter de tipo peaking para las siguientes frequencias
// [50, 100, 156, 220, 331, 440, 622, 880, 1250, 1750, 2500, 3500, 5000, 10000, 20000]
function filters() {
  let f = null;
  let db = jread(CONFIG_FILE).equalizer
  .map(v =>
    v !== 0 ? parseFloat((v < 130 ? (121 - v) : - (v - 140)) / 10) : 0
  );

  hrz.forEach((v, i) => {
    filter.push(
      (f = audioContext.createBiquadFilter(),
      f.type = 'peaking',
      f.frequency.value = v,
      f.Q.value = 1,
      f.gain.value = db[i], f)
    );
  });
}

function moveForward(event, element) {
  forward = _duration * event.offsetX / element.clientWidth;
  const time_m = (forward / 60).toString();

  // Recalcular el tiempo
  minute = parseInt(time_m.slice(0, time_m.lastIndexOf('.')), 10);
  second = Math.floor(parseFloat(time_m.slice(time_m.lastIndexOf('.'))) * 60);
  millisecond = Math.floor(forward * 100) + 1;
  clearInterval(interval);

  // Recalcular el porcentaje de la barra de tiempo
  percent = forward * (100 / _duration);
  isMovingForward = true;
  source.stop(0);
}

module.exports = Object.freeze({
  setSongs,
  playSong,
  prevSong,
  nextSong,
  setFilterVal,
  moveForward
});<commit_msg>was modify the was to display and create the time<commit_after>/**
 * -------------------------- Módulo PlayFile --------------------------------------------------
 * @author Diego Alberto Molina Vera
 *
 * Encargada de reproducir la canción, tocar la siguiente canción o la anterior.
 * Acá se usa la Audio Web API para reproducir la canción y también usar datos
 * obtenidos mediante el buffer. También la API nos permite manipular el archivo de audio
 */
/* --------------------------------------- Módulos ------------------------------------------- */
const worker = new Worker('../../assets/js/timeWorker.js');
const { dialog } = require('electron').remote;
const path = require('path');
require('./commons');

/* --------------------------------------- Variables ------------------------------------------- */
let isMovingForward = false; // Si se está tratando de adelantar la cación a un tiempo determinado
let isSongPlaying = false; // Se ejecutó play sobre el AudioNode
let isNexAble = false; // Se puede reproducir la siguiente canción
let isPrevExec = false; // Solo se agregan las canciones ya reproducidas cuando se presiona next
let position = null; // Posición de la canción actual
let tmpPosition = []; // Posición de la canción anteriormente reproducida
let filePath = ''; // Ruta de la canción
let songs = {}; // Listado de canciones
let notification = null; // Despliega una notificación de la canción que se va a reproducir

// Variables necesarias para trabajar sobre el AudioContext
const audioContext = new window.AudioContext(); // Objeto AudioContext
const xhtr = new XMLHttpRequest(); // Objeto XMLHttpRequest

// Frecuencias
const hrz = [
 40, 80, 90, 100, 120, 150, 200,
 300, 400, 500, 600, 800, 1000,
 1600, 2000, 3000, 4000, 5000, 6000,
 7000, 8000, 10000, 16000
];

let filter = []; // Array con el filtro a usar en distintas frecuencias
let _duration = 0; // Duración máxima de la canción
let _buffer = {}; // Buffer devuelto por decodeAudioData
let source = {}; // Objeto AudioNode
let _connection = []

// Variables para generar el calculo del tiempo transcurrido
// let millisecond = 1;
let interval = null; // Función interval para crear el tiempo de reproducción
let _minute = 0; // Final
let _second = 0; // Final
let forward = 0; // tiempo estimado dónde debería de seguir corriendo la canción al adelantarla
let lapse = 0;
let time = 0; // Tiempo total final

/** --------------------------------------- Funciones --------------------------------------- **/
// Recibe el listado de canciones desde el archivo listSongs.js
function setSongs(_songs) {
  songs = _songs;
  filters();
}

// Retorna un número aleatorio entre 0 y el total de canciones
function shuffle() { return Math.floor(Math.random() * songs.length).toString(); }

// Reproduce una cancion o la pausará
// Responde a todos los posibles estados de una canción
function playSong() {
  if (!isSongPlaying && audioContext.state === 'running') { // Primera vez
    dataSong(shuffle());
    play();

    return 'resume';
  } else if (isSongPlaying && audioContext.state === 'running') { // Ya reproduciendo
    audioContext.suspend().then(() => {
      isSongPlaying = false;
      cancelAnimationFrame(interval);
    });

    return 'paused';
  } else if (!isSongPlaying && audioContext.state === 'suspended') { // Pausado
    isSongPlaying = true;
    startTimer();
    audioContext.resume();

    return 'resume';
  }
}

// Genera el tiempo que lleva reproduciendose la canción
function startTimer() {
  const iter = () => {
    worker.postMessage({ action:'start', per: lapse });
    interval = requestAnimationFrame(iter);
  }
  interval = requestAnimationFrame(iter);

  worker.addEventListener('message', e => {
    $('#time-start').text(e.data.time);
    $('#progress-bar').css(e.data.w);
  });
}

// Límpia el tiempo transcurrido
function stopTimer() {
  if (!isMovingForward) {
    isSongPlaying = false;
    cancelAnimationFrame(interval);
    worker.postMessage({ action: 'stop' });
    $('#time-start').text('00:00');
    _duration = _minute = _second = time = 0;
    if (isNexAble && !isMovingForward) nextSong();
  } else if (isMovingForward) {
    /**
     * La función stop tarda unos milesegundos más que ejecutar la función moveForward.
     * Por lo tanto lo que continua después de detener la canción deberá ser ejecutado
     * dentro de la función onended
     */
    // Se debe crear un nuevo AudioNode, ya que al dar stop el nodo se elimina
    source = audioContext.createBufferSource();

    // Evento que se gatilla al terminar la canción
    source.onended = stopTimer;

    // Conectar todos los nodos
    _connection = [];
    source.buffer = _buffer;
    _connection.push(source);
    _connection.concat(filter);
    _connection.push(audioContext.destination);
    _connection.reduce((a, b) => a.connect(b));

    startTimer();
    source.start(0, forward);
    isMovingForward = false;
    isSongPlaying = true;
  }
}

// Recibe la posición de la canción a buscar en el objeto song
// para desplegarlos en la interfaz
function dataSong(_position) {
  if (position !== null && !isPrevExec) tmpPosition.push(position);

  const infoSong = songs[(position = parseInt(_position, 10))];
  filePath = infoSong.filename; // Ruta donde se encuentra el archivo a reproducir

  // Título de la canción
  $('#song-title').data({position}).child().each(v => { v.text(infoSong.title); });
  // Artista
  $('#artist').child().each(v => { v.text(infoSong.artist); });
  // Album
  $('#album').child().each(v => { v.text(infoSong.album); });

  // Mostrar notificación
  if (notification !== null) notification.close();

  notification = null

  notification = new Notification(infoSong.title.replace(/\ /g, ' '), {
    lang: 'US',
    tag: 'song',
    body: `${infoSong.artist.replace(/\ /g, ' ')} from ${infoSong.album.replace(/\ /g, ' ')}`,
    icon: path.join(__dirname, '..', 'img', 'play.png')
  });
}

// EJecuta, por medio de la Audio Web API, la canción.
// Se obtiene un array buffer con info útil para usar
function play() {
  // Creamos un Buffer que contendrá la canción
  source = audioContext.createBufferSource();

  // Leer erl achivo de audio
  xhtr.open('GET', `file://${filePath}`, true);
  xhtr.responseType = 'arraybuffer';
  xhtr.onload = () => {
    audioContext.decodeAudioData(xhtr.response).then(buffer => {
      // Para ser usado al momento de querer adelantar la canción
      // El buffer nos entrega la duración de la canción.
      // La duración de la cación está en segundos, por ende hay que pasarla a minutos.
      _buffer = buffer;
      time = ((_duration = _buffer.duration) / 60).toString();
      _minute = parseInt(time.slice(0, time.lastIndexOf('.')), 10);
      _second = Math.floor(parseFloat(time.slice(time.lastIndexOf('.'))) * 60);
      lapse = 100 / _duration; // Porcentaje a usar por cada segundo en la barra de progreso
      $('#time-end').text(`${_minute > 9 ? `${_minute}` : `0${_minute}`}${_second > 9 ? `:${_second}` : `:0${_second}`}`);

      // Evento que se gatilla al terminar la canción
      source.onended = stopTimer;

      // Conectar todos los nodos
      source.buffer = _buffer;
      _connection = [];
      _connection.push(source);
      _connection.concat(filter);
      _connection.push(audioContext.destination);
      _connection.reduce((a, b) => a.connect(b));

      // Inicializar el tiempo y la canción
      startTimer();
      source.start(0);
      isNexAble = isSongPlaying = true;
    }, reason => {
      dialog.showErrorBox('Error [002]', `${jread(LANG_FILE)[jread(CONFIG_FILE).lang].alerts.playSong}\n${reason}`);
      return;
    });
  };
  xhtr.send(null);
}

// Reproduce la siguiente canción.
// Esta función se comparte cuando se genera la lista de canciones,
// ya que al dar click sobre una canción, la que se reproduce es otra ("siguiente").
function nextSong(_position = -1) {
  isPrevExec = false;
  if (_position !== -1) {
    // ver si está reproduciendose o no
    if (isSongPlaying && audioContext.state === 'running' ||
      !isSongPlaying && audioContext.state === 'suspended') {
      if (!isSongPlaying && audioContext.state === 'suspended') audioContext.resume();

      isNexAble = false;
      source.stop(0);
      source = null;
    }
    dataSong(_position)
    play();
  } else {
    // Ver en primera instancia si es posible reproducir la siguiente canción.
    // Esto va a depender de si se ejecutó ya una canción.
    // Si no se válida, podrían reproducirse varias pistas a la vez - No queremos esto :-(
    if (isNexAble) {
      isNexAble = false;
      dataSong(jread(CONFIG_FILE).shuffle ? shuffle() : (songs.length - 1 > position ? position + 1 : 0));
      // si está sonando la canción, esta se debe detener para tocar la nueva
      if (isSongPlaying && audioContext.state === 'running' ||
         !isSongPlaying && audioContext.state === 'suspended') {
        // Verificar si el contexto está pausado o no.
        // Si está pausado no se reproducirá una nueva pista
        if (!isSongPlaying && audioContext.state === 'suspended') audioContext.resume();

        source.stop(0);
        source = null;
      }

      play();
    }
  }
}

// Reproducirá la canción anterior
function prevSong() {
  if (isNexAble && tmpPosition.length > 0) {
    isNexAble = false;
    isPrevExec = true;
    dataSong(tmpPosition.pop());

    // si está sonando la canción, esta se debe detener para tocar la nueva
    if (isSongPlaying && audioContext.state === 'running') {
      source.stop(0);
      source = null;
    }
    // Verificar si el contexto está pausado o no.
    // Si está pausado no se reproducirá una nueva pista
    if (!isSongPlaying && audioContext.state === 'suspended') audioContext.resume();
    play();
  }
}

// Cambia los valores en la frecuencia específica
function setFilterVal(a, b) {
  filter[a].gain.setValueAtTime(b, audioContext.currentTime);
}

// Crea y asigna BiquadFilter de tipo peaking para las siguientes frequencias
// [50, 100, 156, 220, 331, 440, 622, 880, 1250, 1750, 2500, 3500, 5000, 10000, 20000]
function filters() {
  let f = null;
  let db = jread(CONFIG_FILE).equalizer
  .map(v =>
    v !== 0 ? parseFloat((v < 130 ? (121 - v) : - (v - 140)) / 10) : 0
  );

  hrz.forEach((v, i) => {
    filter.push(
      (f = audioContext.createBiquadFilter(),
      f.type = 'peaking',
      f.frequency.value = v,
      f.Q.value = 1,
      f.gain.value = db[i], f)
    );
  });
}

function moveForward(event, element) {
  forward = _duration * event.offsetX / element.clientWidth;
  const time_m = (forward / 60).toString();

  // Recalcular el tiempo
  minute = parseInt(time_m.slice(0, time_m.lastIndexOf('.')), 10);
  second = Math.floor(parseFloat(time_m.slice(time_m.lastIndexOf('.'))) * 60);
  millisecond = Math.floor(forward * 100) + 1;
  cancelAnimationFrame(interval);

  // Recalcular el porcentaje de la barra de tiempo
  percent = forward * (100 / _duration);
  isMovingForward = true;
  source.stop(0);
}

module.exports = Object.freeze({
  setSongs,
  playSong,
  prevSong,
  nextSong,
  setFilterVal,
  moveForward
});<|endoftext|>


<commit_before>
import React from 'react/addons';
import moment from 'moment';
import DateUtils from './utils/DateUtils.js';
import DayPicker from './daypicker/DayPicker';
import MonthPicker from './monthpicker/MonthPicker';
import YearPicker from './yearpicker/YearPicker';

const DatePicker = React.createClass({

  /* eslint-disable key-spacing */
  propTypes: {
    onChange:             React.PropTypes.func.isRequired,
    date:                 DateUtils.evaluateDateProp,
    initialDate:          DateUtils.evaluateDateProp,
    minDate:              DateUtils.evaluateDateProp,
    maxDate:              DateUtils.evaluateDateProp,
    locale:               React.PropTypes.string,
    startMode:            React.PropTypes.string,
    fixedMode:            React.PropTypes.bool,
    floating:             React.PropTypes.bool,
    closeOnClickOutiside: React.PropTypes.bool, // used only with DatePickerInput
    className:            React.PropTypes.string,
    style:                React.PropTypes.object
  },
  /* eslint-enable key-spacing */

  getDefaultProps() {
    return {
      startMode: 'day',
      className: '',
      style: {}
    };
  },

  getInitialState() {
    if (this.props.locale) {
      moment.locale(this.props.locale);
      if (moment.locale() !== this.props.locale) {
        console.warn(`Setting "${this.props.locale}" as locale failed. Did you import it correctly?`);
      }
    }
    return this.getStateFromProps(this.props);
  },

  getStateFromProps(_props) {
    const date = typeof _props.date === 'string' ? moment(_props.date, this.getFormat(), true) : moment(_props.date);
    const initialDate = typeof _props.initialDate === 'string' ? moment(_props.initialDate, this.getFormat(), true) : moment(_props.initialDate);
    const visibleDate = _props.date ? date.clone() : initialDate; // must be copy, otherwise they get linked
    return {
      date: _props.date ? date.clone() : undefined,
      visibleDate: visibleDate,
      mode: _props.startMode
    };
  },

  stopPropagation(e) {
    if (this.props.closeOnClickOutiside) {
      e.stopPropagation();
    }
  },

  onChangeVisibleDate(date) {
    this.setState({visibleDate: date});
  },

  onChangeSelectedDate(date) {
    this.setState({
      visibleDate: date.clone(), // must be copy, otherwise they get linked
      date: date
    });
    this.props.onChange(date.toDate());
  },

  onChangeMode(mode) {
    this.setState({ mode });
  },

  getDayPicker() {
    return (
      <DayPicker
        date={this.state.date}
        visibleDate={this.state.visibleDate}
        minDate={this.props.minDate}
        maxDate={this.props.maxDate}
        onChangeVisibleDate={this.onChangeVisibleDate}
        onSelectDate={this.onChangeSelectedDate}
        onChangeMode={this.onChangeMode}
        mode={this.state.mode}
        fixedMode={this.props.fixedMode}
        className={this.props.className}
      />
    );
  },

  getMonthPicker() {
    return (
      <MonthPicker
        date={this.state.date}
        visibleDate={this.state.visibleDate}
        minDate={this.props.minDate}
        maxDate={this.props.maxDate}
        onChangeVisibleDate={this.onChangeVisibleDate}
        onSelectDate={this.onChangeSelectedDate}
        onChangeMode={this.onChangeMode}
        mode={this.state.mode}
        fixedMode={this.props.fixedMode}
        className={this.props.className}
      />
    );
  },

  getYearPicker() {
    return (
      <YearPicker
        date={this.state.date}
        visibleDate={this.state.visibleDate}
        minDate={this.props.minDate}
        maxDate={this.props.maxDate}
        onChangeVisibleDate={this.onChangeVisibleDate}
        onSelectDate={this.onChangeSelectedDate}
        onChangeMode={this.onChangeMode}
        mode={this.state.mode}
        fixedMode={this.props.fixedMode}
        className={this.props.className}
      />
    );
  },

  render() {
    let picker;
    switch (this.state.mode) {
      case 'day':
        picker = this.getDayPicker();
        break;

      case 'month':
        picker = this.getMonthPicker();
        break;

      case 'year':
        picker = this.getYearPicker();
        break;
    }

    const floating = this.props.floating ? 'floating' : '';
    return (
      <div
        className={`react-datepicker ${floating} ${this.props.className}`}
        style={this.props.style}
        onClick={this.stopPropagation}>
        {picker}
      </div>
    );
  },

  componentWillReceiveProps(nextProps) {
    if (nextProps.date) {
      this.setState(this.getStateFromProps(nextProps));
    }
  }

});

export default DatePicker;
<commit_msg>Warn for missing locale only in development builds<commit_after>
import React from 'react/addons';
import moment from 'moment';
import DateUtils from './utils/DateUtils.js';
import DayPicker from './daypicker/DayPicker';
import MonthPicker from './monthpicker/MonthPicker';
import YearPicker from './yearpicker/YearPicker';

const DatePicker = React.createClass({

  /* eslint-disable key-spacing */
  propTypes: {
    onChange:             React.PropTypes.func.isRequired,
    date:                 DateUtils.evaluateDateProp,
    initialDate:          DateUtils.evaluateDateProp,
    minDate:              DateUtils.evaluateDateProp,
    maxDate:              DateUtils.evaluateDateProp,
    locale:               React.PropTypes.string,
    startMode:            React.PropTypes.string,
    fixedMode:            React.PropTypes.bool,
    floating:             React.PropTypes.bool,
    closeOnClickOutiside: React.PropTypes.bool, // used only with DatePickerInput
    className:            React.PropTypes.string,
    style:                React.PropTypes.object
  },
  /* eslint-enable key-spacing */

  getDefaultProps() {
    return {
      startMode: 'day',
      className: '',
      style: {}
    };
  },

  getInitialState() {
    if (this.props.locale) {
      moment.locale(this.props.locale);
      if (process.env.NODE_ENV !== 'production' && moment.locale() !== this.props.locale) {
        console.warn(`Setting "${this.props.locale}" as locale failed. Did you import it correctly?`);
      }
    }
    return this.getStateFromProps(this.props);
  },

  getStateFromProps(_props) {
    const date = typeof _props.date === 'string' ? moment(_props.date, this.getFormat(), true) : moment(_props.date);
    const initialDate = typeof _props.initialDate === 'string' ? moment(_props.initialDate, this.getFormat(), true) : moment(_props.initialDate);
    const visibleDate = _props.date ? date.clone() : initialDate; // must be copy, otherwise they get linked
    return {
      date: _props.date ? date.clone() : undefined,
      visibleDate: visibleDate,
      mode: _props.startMode
    };
  },

  stopPropagation(e) {
    if (this.props.closeOnClickOutiside) {
      e.stopPropagation();
    }
  },

  onChangeVisibleDate(date) {
    this.setState({visibleDate: date});
  },

  onChangeSelectedDate(date) {
    this.setState({
      visibleDate: date.clone(), // must be copy, otherwise they get linked
      date: date
    });
    this.props.onChange(date.toDate());
  },

  onChangeMode(mode) {
    this.setState({ mode });
  },

  getDayPicker() {
    return (
      <DayPicker
        date={this.state.date}
        visibleDate={this.state.visibleDate}
        minDate={this.props.minDate}
        maxDate={this.props.maxDate}
        onChangeVisibleDate={this.onChangeVisibleDate}
        onSelectDate={this.onChangeSelectedDate}
        onChangeMode={this.onChangeMode}
        mode={this.state.mode}
        fixedMode={this.props.fixedMode}
        className={this.props.className}
      />
    );
  },

  getMonthPicker() {
    return (
      <MonthPicker
        date={this.state.date}
        visibleDate={this.state.visibleDate}
        minDate={this.props.minDate}
        maxDate={this.props.maxDate}
        onChangeVisibleDate={this.onChangeVisibleDate}
        onSelectDate={this.onChangeSelectedDate}
        onChangeMode={this.onChangeMode}
        mode={this.state.mode}
        fixedMode={this.props.fixedMode}
        className={this.props.className}
      />
    );
  },

  getYearPicker() {
    return (
      <YearPicker
        date={this.state.date}
        visibleDate={this.state.visibleDate}
        minDate={this.props.minDate}
        maxDate={this.props.maxDate}
        onChangeVisibleDate={this.onChangeVisibleDate}
        onSelectDate={this.onChangeSelectedDate}
        onChangeMode={this.onChangeMode}
        mode={this.state.mode}
        fixedMode={this.props.fixedMode}
        className={this.props.className}
      />
    );
  },

  render() {
    let picker;
    switch (this.state.mode) {
      case 'day':
        picker = this.getDayPicker();
        break;

      case 'month':
        picker = this.getMonthPicker();
        break;

      case 'year':
        picker = this.getYearPicker();
        break;
    }

    const floating = this.props.floating ? 'floating' : '';
    return (
      <div
        className={`react-datepicker ${floating} ${this.props.className}`}
        style={this.props.style}
        onClick={this.stopPropagation}>
        {picker}
      </div>
    );
  },

  componentWillReceiveProps(nextProps) {
    if (nextProps.date) {
      this.setState(this.getStateFromProps(nextProps));
    }
  }

});

export default DatePicker;
<|endoftext|>


<commit_before>var batchService = module.exports = {};

var _ = require('lodash');
var q = require('q');
var logger = require('winston');
var uuid = require('node-uuid');
var csv = require('csv');
var mongoose = require('mongoose');
var BatchJob = require('./batchJob').model;
var BatchResult = require('./batchResult').model;
var mongoService = require('../mongoService');
var fileService = require('../file/fileService');

batchService.states = {
    standby : 'Sleeping',
    processing : 'Processing',
    searching: 'Searching...',
    inactive : 'Disabled'
};

batchService.batchHandlers = {};

batchService.processes = [
    {
        id: uuid.v4(),
        name: "Batch processor",
        state : batchService.states.standby
    }
];

batchService.batchStatuses = {
    awaitingProcessing: 'Awaiting processing',
    failed:'Failed',
    cancelled:'Cancelled',
    inProgress:'In progress',
    completed:'Completed',
    completedWithFailures:'Completed with failures'
};

batchService.startBatchProcessors = function(){
    batchService.processes.forEach(function(process){
        logger.log("info","["+process.name+"]" + " has been started");
        setInterval(batchService.processorTick, 5000, process);
    });

    logger.log("info","[failed batch job checker]" + " has been started");
    setInterval(batchService.failedBatchJobChecker, 10000);
};

batchService.loadBatchHandler = function(key, handler){
    batchService.batchHandlers[key] = handler;
};

/**
 * Finds all in progress batch jobs and check they are being processed by a processor.
 * If no processor claims the batch job mark it as failed.
 */
batchService.failedCheckerState = batchService.states.standby;

batchService.failedBatchJobChecker = function(){
    if (batchService.failedCheckerState == batchService.states.standby){
        batchService.failedCheckerState = batchService.states.processing;
        logger.log('debug',"[failed batch job checker] started looking for stuck batch jobs");
        mongoService.find(BatchJob, {status: batchService.batchStatuses.inProgress}).then(function(batchesInProgress){
            var proms = batchesInProgress.map(function(batchInProgress){
                if(!batchService.doesAnyProcessContainBatch(batchInProgress)){
                    //batch in progress that is not in a processor. mark it as failed
                    batchInProgress.status = batchService.batchStatuses.failed;
                    return mongoService.savePromise(batchInProgress).then(function(result){
                        logger.log("info","[failed batch job checker] has marked batch job " +
                            " id: " + batchInProgress._id +
                            " name: " + batchInProgress.type +
                            " as Failed because nothing is processing it");
                        return result;
                    }, function(updateFailure){
                        batchService.failedCheckerState = batchService.states.standby;
                        logger.log("info","[failed batch job checker] had an error trying to update a batch job to failed", updateFailure);
                    });
                } else {
                    return q(true);
                }
            });
            q.all(proms).then(function(){
                batchService.failedCheckerState = batchService.states.standby;
                logger.log('debug',"[failed batch job checker] finished looking for stuck batch jobs");
            }, function(someError){
                logger.log("info","[failed batch job checker] has had an error", someError);
                batchService.failedCheckerState = batchService.states.standby;
            });
        }, function(err){
            logger.log("info","[failed batch job checker] has had an error", err);
            batchService.failedCheckerState = batchService.states.standby;
        });
    } else {
        logger.log("info","[failed batch job checker] is busy did not fire at this time");
    }
};

batchService.doesAnyProcessContainBatch = function(batch){
    return _.any(batchService.processes, function(process){
         return batchService.doesProcessContainBatch(process, batch);
     });
};

batchService.doesProcessContainBatch = function(process, batch){
    return process.state == batchService.states.processing &&
        process.processingBatch != null &&
        _.isEqual(process.processingBatch._id, batch._id);
};

batchService.processorTick = function(processor){
    if (processor.state == batchService.states.standby){
        batchService.executeProcessor(processor);
    } else {
        logger.log("info",processor.name + " is busy");
    }
};

batchService.executeProcessor = function(processor){
    processor.state = batchService.states.searching;
    //find a batch that requires processing
    var query = {status: batchService.batchStatuses.awaitingProcessing};
    var update = {status: batchService.batchStatuses.inProgress};
    var options = {sort : {createdAt : 1}};
    BatchJob.findOneAndUpdate(query, update, options, function(err, batchToProcess) {
        if (err) {
            logger.log("info",processor.name + " had an error reading batch", err);
            batchService.clearProcessor(processor);
        } else if (batchToProcess != null) {
            logger.log("info",processor.name + " started processing batch job " + batchToProcess.type);
            processor.state = batchService.states.processing;
            processor.processingBatch = batchToProcess;
            batchService.processBatch(processor.processingBatch).then(function(){
                logger.log('info',processor.name + " finished processing batch job " + batchToProcess.type);
                batchToProcess.status = batchService.batchStatuses.completed;
                mongoService.savePromise(batchToProcess).then(function(){
                    batchService.clearProcessor(processor);
                }, function(){
                    logger.log('info',processor.name + " had an error updating batch", err);
                    batchService.clearProcessor(processor);
                });
            }, function(batchProcessError){
                logger.log("info", processor.name + " had an error processing batch job:" + batchProcessError);
                batchToProcess.status = batchService.batchStatuses.failed;
                mongoService.savePromise(batchToProcess).then(function(){
                    batchService.clearProcessor(processor);
                }, function(){
                    logger.log("info", processor.name + " had an error updating batch", err);
                    batchService.clearProcessor(processor);
                });
            });
        } else {
            logger.log('debug',processor.name + " found no batch jobs to process");
            batchService.clearProcessor(processor);
        }
    });
};

batchService.clearProcessor = function(processor){
    delete processor.processingBatch;
    processor.state = batchService.states.standby;
};

batchService.processBatch = function(batchJob){
    if (_.contains(_.keys(batchService.batchHandlers), batchJob.type)){
        return batchService.batchHandlers[batchJob.type](batchJob);
    } else {
        return q.reject("unknown batch of type: " + batchJob.type);
    }
};

batchService.batchJobResultOptions = {
    'failed':'Failed',
    'success':'Success'
};

batchService.getBatchResultFromBoolean = function(boolean){
    if (boolean){
        return batchService.batchJobResultOptions.success;
    } else {
        return batchService.batchJobResultOptions.failed;
    }
};

batchService.getBatchInfo = function(){
    return batchService.processes[0];
};

batchService.createBatch = function(type, metadata, createIfNotAwaiting) {
    //generate the batch model
    var batch = new BatchJob({
        type:type,
        metadata: metadata,
        status: batchService.batchStatuses.awaitingProcessing
    });
    //then check the fields
    var error = batchService.hasError(batch);
    if (error){
        return q.reject(error);
    } else {
        if (createIfNotAwaiting === true){
            return mongoService.findOne(BatchJob, {type:type, status: batchService.batchStatuses.awaitingProcessing}).then(function(result){
                if (result != null){
                    return result;
                } else {
                    return mongoService.savePromise(batch);
                }
            });
        } else {
            return mongoService.savePromise(batch);
        }
    }
};

batchService.updateBatchJob = function(batchJob){
    return mongoService.savePromise(batchJob);
};

batchService.hasError = function(batch){
    var error;
    var typeValid = batch.type && batch.type.length > 0;
    if (!typeValid){
        if (!error){
            error = {errors:[]};
        }
        error.message = 'invalid field';
        error.errors.push('type is required');
    }

    if (error){
        return error;
    } else {
        return null;
    }
};

batchService.createBatchHandler = function(req, file){
    return batchService.createBatch(req.param('batchType'), {fileName: req.headers.uploadfilename, fileId : file._id}).then(function(batch){
        return q(batch);
    }, function(batchCreationError){
        logger.log("error","batch creation error");
        return q.reject({'error':batchCreationError});
    });
};

batchService.createBatchResult = function(batchRef, recordNumber, status, startDate, raw, stepResults){
    var batchResult = new BatchResult({
        batchRef: batchRef,
        recordNumber: recordNumber,
        status: status,
        startDate: startDate,
        endDate: new Date(),
        raw: raw,
        stepResults: stepResults
    });
    return mongoService.savePromise(batchResult)
};

batchService.processBatchJobFile = function(batchJob, rowProcessor){
    var deferred = q.defer();
    if (batchJob.metadata != null && batchJob.metadata.fileId != null){
        //find the file and stream it in
        var fileReadStream =  fileService.getFileReadStream(batchJob.metadata.fileId);
        var recordCount = 0;
        fileReadStream.on('error', function(fileReadError){
            logger.log("error","error streaming from gridfs", fileReadError);
            deferred.reject(fileReadError);
        });

        var parser = csv.parse();

        parser.on('data', function(record){
            parser.pause();
            recordCount += 1;
            var index = recordCount;
            var recordStart = new Date();
            return rowProcessor(record).then(function(resultInfo) {
                var resultType = batchService.getBatchResultFromBoolean(resultInfo.isSuccessful);
                var batchResult = new BatchResult({
                    batchRef: batchJob._id,
                    recordNumber: index,
                    status: resultType,
                    startDate: recordStart,
                    endDate: new Date(),
                    raw: record,
                    stepResults: resultInfo.stepResults
                });
                return mongoService.savePromise(batchResult).then(function(){
                    parser.resume();
                });
            });
        });

        parser.on('finish', function(){
            deferred.resolve({results: true});
        });

        parser.on('error', function(parserError){
            logger.log("error","error parsing csv", parserError);
            deferred.reject(parserError);
        });

        fileReadStream.pipe(parser);
    } else {
        deferred.reject({error: "batch job does not contain enough data to process"});
    }
    return deferred.promise;
};

fileService.createPostUploadHandler('batch', batchService.createBatchHandler);<commit_msg>Removed unused function<commit_after>var batchService = module.exports = {};

var _ = require('lodash');
var q = require('q');
var logger = require('winston');
var uuid = require('node-uuid');
var csv = require('csv');
var mongoose = require('mongoose');
var BatchJob = require('./batchJob').model;
var BatchResult = require('./batchResult').model;
var mongoService = require('../mongoService');
var fileService = require('../file/fileService');

batchService.states = {
    standby : 'Sleeping',
    processing : 'Processing',
    searching: 'Searching...',
    inactive : 'Disabled'
};

batchService.batchHandlers = {};

batchService.processes = [
    {
        id: uuid.v4(),
        name: "Batch processor",
        state : batchService.states.standby
    }
];

batchService.batchStatuses = {
    awaitingProcessing: 'Awaiting processing',
    failed:'Failed',
    cancelled:'Cancelled',
    inProgress:'In progress',
    completed:'Completed',
    completedWithFailures:'Completed with failures'
};

batchService.startBatchProcessors = function(){
    batchService.processes.forEach(function(process){
        logger.log("info","["+process.name+"]" + " has been started");
        setInterval(batchService.processorTick, 5000, process);
    });

    logger.log("info","[failed batch job checker]" + " has been started");
    setInterval(batchService.failedBatchJobChecker, 10000);
};

batchService.loadBatchHandler = function(key, handler){
    batchService.batchHandlers[key] = handler;
};

/**
 * Finds all in progress batch jobs and check they are being processed by a processor.
 * If no processor claims the batch job mark it as failed.
 */
batchService.failedCheckerState = batchService.states.standby;

batchService.failedBatchJobChecker = function(){
    if (batchService.failedCheckerState == batchService.states.standby){
        batchService.failedCheckerState = batchService.states.processing;
        logger.log('debug',"[failed batch job checker] started looking for stuck batch jobs");
        mongoService.find(BatchJob, {status: batchService.batchStatuses.inProgress}).then(function(batchesInProgress){
            var proms = batchesInProgress.map(function(batchInProgress){
                if(!batchService.doesAnyProcessContainBatch(batchInProgress)){
                    //batch in progress that is not in a processor. mark it as failed
                    batchInProgress.status = batchService.batchStatuses.failed;
                    return mongoService.savePromise(batchInProgress).then(function(result){
                        logger.log("info","[failed batch job checker] has marked batch job " +
                            " id: " + batchInProgress._id +
                            " name: " + batchInProgress.type +
                            " as Failed because nothing is processing it");
                        return result;
                    }, function(updateFailure){
                        batchService.failedCheckerState = batchService.states.standby;
                        logger.log("info","[failed batch job checker] had an error trying to update a batch job to failed", updateFailure);
                    });
                } else {
                    return q(true);
                }
            });
            q.all(proms).then(function(){
                batchService.failedCheckerState = batchService.states.standby;
                logger.log('debug',"[failed batch job checker] finished looking for stuck batch jobs");
            }, function(someError){
                logger.log("info","[failed batch job checker] has had an error", someError);
                batchService.failedCheckerState = batchService.states.standby;
            });
        }, function(err){
            logger.log("info","[failed batch job checker] has had an error", err);
            batchService.failedCheckerState = batchService.states.standby;
        });
    } else {
        logger.log("info","[failed batch job checker] is busy did not fire at this time");
    }
};

batchService.doesAnyProcessContainBatch = function(batch){
    return _.any(batchService.processes, function(process){
         return batchService.doesProcessContainBatch(process, batch);
     });
};

batchService.doesProcessContainBatch = function(process, batch){
    return process.state == batchService.states.processing &&
        process.processingBatch != null &&
        _.isEqual(process.processingBatch._id, batch._id);
};

batchService.processorTick = function(processor){
    if (processor.state == batchService.states.standby){
        batchService.executeProcessor(processor);
    } else {
        logger.log("info",processor.name + " is busy");
    }
};

batchService.executeProcessor = function(processor){
    processor.state = batchService.states.searching;
    //find a batch that requires processing
    var query = {status: batchService.batchStatuses.awaitingProcessing};
    var update = {status: batchService.batchStatuses.inProgress};
    var options = {sort : {createdAt : 1}};
    BatchJob.findOneAndUpdate(query, update, options, function(err, batchToProcess) {
        if (err) {
            logger.log("info",processor.name + " had an error reading batch", err);
            batchService.clearProcessor(processor);
        } else if (batchToProcess != null) {
            logger.log("info",processor.name + " started processing batch job " + batchToProcess.type);
            processor.state = batchService.states.processing;
            processor.processingBatch = batchToProcess;
            batchService.processBatch(processor.processingBatch).then(function(){
                logger.log('info',processor.name + " finished processing batch job " + batchToProcess.type);
                batchToProcess.status = batchService.batchStatuses.completed;
                mongoService.savePromise(batchToProcess).then(function(){
                    batchService.clearProcessor(processor);
                }, function(){
                    logger.log('info',processor.name + " had an error updating batch", err);
                    batchService.clearProcessor(processor);
                });
            }, function(batchProcessError){
                logger.log("info", processor.name + " had an error processing batch job:" + batchProcessError);
                batchToProcess.status = batchService.batchStatuses.failed;
                mongoService.savePromise(batchToProcess).then(function(){
                    batchService.clearProcessor(processor);
                }, function(){
                    logger.log("info", processor.name + " had an error updating batch", err);
                    batchService.clearProcessor(processor);
                });
            });
        } else {
            logger.log('debug',processor.name + " found no batch jobs to process");
            batchService.clearProcessor(processor);
        }
    });
};

batchService.clearProcessor = function(processor){
    delete processor.processingBatch;
    processor.state = batchService.states.standby;
};

batchService.processBatch = function(batchJob){
    if (_.contains(_.keys(batchService.batchHandlers), batchJob.type)){
        return batchService.batchHandlers[batchJob.type](batchJob);
    } else {
        return q.reject("unknown batch of type: " + batchJob.type);
    }
};

batchService.batchJobResultOptions = {
    'failed':'Failed',
    'success':'Success'
};

batchService.getBatchResultFromBoolean = function(boolean){
    if (boolean){
        return batchService.batchJobResultOptions.success;
    } else {
        return batchService.batchJobResultOptions.failed;
    }
};

batchService.createBatch = function(type, metadata, createIfNotAwaiting) {
    //generate the batch model
    var batch = new BatchJob({
        type:type,
        metadata: metadata,
        status: batchService.batchStatuses.awaitingProcessing
    });
    //then check the fields
    var error = batchService.hasError(batch);
    if (error){
        return q.reject(error);
    } else {
        if (createIfNotAwaiting === true){
            return mongoService.findOne(BatchJob, {type:type, status: batchService.batchStatuses.awaitingProcessing}).then(function(result){
                if (result != null){
                    return result;
                } else {
                    return mongoService.savePromise(batch);
                }
            });
        } else {
            return mongoService.savePromise(batch);
        }
    }
};

batchService.updateBatchJob = function(batchJob){
    return mongoService.savePromise(batchJob);
};

batchService.hasError = function(batch){
    var error;
    var typeValid = batch.type && batch.type.length > 0;
    if (!typeValid){
        if (!error){
            error = {errors:[]};
        }
        error.message = 'invalid field';
        error.errors.push('type is required');
    }

    if (error){
        return error;
    } else {
        return null;
    }
};

batchService.createBatchHandler = function(req, file){
    return batchService.createBatch(req.param('batchType'), {fileName: req.headers.uploadfilename, fileId : file._id}).then(function(batch){
        return q(batch);
    }, function(batchCreationError){
        logger.log("error","batch creation error");
        return q.reject({'error':batchCreationError});
    });
};

batchService.createBatchResult = function(batchRef, recordNumber, status, startDate, raw, stepResults){
    var batchResult = new BatchResult({
        batchRef: batchRef,
        recordNumber: recordNumber,
        status: status,
        startDate: startDate,
        endDate: new Date(),
        raw: raw,
        stepResults: stepResults
    });
    return mongoService.savePromise(batchResult)
};

batchService.processBatchJobFile = function(batchJob, rowProcessor){
    var deferred = q.defer();
    if (batchJob.metadata != null && batchJob.metadata.fileId != null){
        //find the file and stream it in
        var fileReadStream =  fileService.getFileReadStream(batchJob.metadata.fileId);
        var recordCount = 0;
        fileReadStream.on('error', function(fileReadError){
            logger.log("error","error streaming from gridfs", fileReadError);
            deferred.reject(fileReadError);
        });

        var parser = csv.parse();

        parser.on('data', function(record){
            parser.pause();
            recordCount += 1;
            var index = recordCount;
            var recordStart = new Date();
            return rowProcessor(record).then(function(resultInfo) {
                var resultType = batchService.getBatchResultFromBoolean(resultInfo.isSuccessful);
                var batchResult = new BatchResult({
                    batchRef: batchJob._id,
                    recordNumber: index,
                    status: resultType,
                    startDate: recordStart,
                    endDate: new Date(),
                    raw: record,
                    stepResults: resultInfo.stepResults
                });
                return mongoService.savePromise(batchResult).then(function(){
                    parser.resume();
                });
            });
        });

        parser.on('finish', function(){
            deferred.resolve({results: true});
        });

        parser.on('error', function(parserError){
            logger.log("error","error parsing csv", parserError);
            deferred.reject(parserError);
        });

        fileReadStream.pipe(parser);
    } else {
        deferred.reject({error: "batch job does not contain enough data to process"});
    }
    return deferred.promise;
};

fileService.createPostUploadHandler('batch', batchService.createBatchHandler);<|endoftext|>


<commit_before>import React from 'react';
import * as Sentry from '@sentry/browser';

export default class Error extends React.Component {
  static getInitialProps({ res, err }) {
    const statusCode = res ? res.statusCode : err ? err.statusCode : null;
    return { statusCode };
  }

  componentDidMount() {
    let location;

    if (typeof window !== 'undefined') {
      Sentry.captureException(new Error(`${window.location.href}`));
    }

    // Maybe redirect!?
    console.log(window.location.pathname);
  }

  render() {
    return (

          Uh oh, we couldn't find this page! Maybe it doesn't exist anymore! 😔

          Go back to the Expo documentation

    );
  }
}
<commit_msg>[docs] Use captureMessage instead of exception<commit_after>import React from 'react';
import * as Sentry from '@sentry/browser';

export default class Error extends React.Component {
  static getInitialProps({ res, err }) {
    const statusCode = res ? res.statusCode : err ? err.statusCode : null;
    return { statusCode };
  }

  componentDidMount() {
    let location;

    if (typeof window !== 'undefined') {
      Sentry.captureMessage(`404: ${window.location.href}`);
    }

    // Maybe redirect!?
    console.log(window.location.pathname);
  }

  render() {
    return (

          Uh oh, we couldn't find this page! Maybe it doesn't exist anymore! 😔

          Go back to the Expo documentation

    );
  }
}
<|endoftext|>