<commit_before>(function() {
  "use strict";

  var testFixture = function(require, exports) {
    var chai = require('chai');
    var expect = chai.expect;

    var base = require('../base');
    var getRealArity = base.getRealArity;

    var object = require('../object');

    // Import utility functions
    var testUtils = require('./testUtils');
    var exportsProperty = testUtils.exportsProperty;
    var exportsFunction = testUtils.exportsFunction;
    var testCurriedFunction = testUtils.testCurriedFunction;

    describe('Object exports', function() {
      var expectedFunctions = ['callPropWithArity', 'callProp', 'hasOwnProperty',
                               'hasProperty', 'instanceOf', 'isPrototypeOf', 'createObject',
                               'createObjectWithProps'];

      // Automatically generate existence tests for each expected function
      expectedFunctions.forEach(function(f) {
        it('object.js exports \'' + f + '\' property', exportsProperty(object, f));
        it('\'' + f + '\' property of object.js is a function', exportsFunction(object, f));
      });
    });

    describe('callPropWithArity', function() {
      var callPropWithArity = object.callPropWithArity;

      it('callPropWithArity has correct \'real\' arity', function() {
        expect(getRealArity(callPropWithArity)).to.equal(2);
      });

      // Test generation
      var makeReturnedCurriedArityTest = function(i) {
        return function() {
          var fn = callPropWithArity('prop', i);

          expect(fn.length).to.equal(1);
        };
      };

      var makeReturnedArityTest = function(i) {
        return function() {
          var fn = callPropWithArity('prop', i);

          expect(getRealArity(fn)).to.equal(i + 1);
        };
      };

      var functionalityArgs = [1, true, null, function() {}, []];
      var makeCalledTest = function(i) {
        return function() {
          var args = functionalityArgs.slice(0, i);
          var obj = {called: false, calledProp: function() {this.called = true;}};
          var caller = callPropWithArity('calledProp', i);
          var result = caller.apply(null, args.concat([obj]));

          expect(obj.called).to.be.true;
        }
      };

      var makeReturnedValueTest = function(i) {
        return function() {
          var expected = functionalityArgs.slice(0, i);
          var obj = {calledProp: function() {return [].slice.call(arguments);}};
          var obj2 = {calledProp: function() {return 42;}};
          var caller = callPropWithArity('calledProp', i);
          var result = caller.apply(null, expected.concat([obj]));
          var result2 = caller.apply(null, expected.concat([obj2]));

          expect(result).to.deep.equal(expected);
          expect(result2).to.equal(42);
        };
      };

      for (var i = 0; i < 6; i++) {
        it('Returned function has correct arity for arity' + i,
           makeReturnedCurriedArityTest(i));

        it('Returned function has correct \'real\' arity' + i,
           makeReturnedArityTest(i));

        it('Returned function calls prop on given object' + i,
           makeCalledTest(i));

        it('Returned function returns correct result when called' + i,
           makeReturnedValueTest(i));

        // The returned function should be curried
        var testObj = {prop: function(x) {return x;}};
        var caller = callPropWithArity('prop', 1);
        testCurriedFunction('Returned function', caller, [2, testObj]);
      }

      // callPropWithArity should itself be curried
      var testObj = {property: function() {return 42;}};
      var args = {firstArgs: ['property', 0], thenArgs: [testObj]};
      testCurriedFunction('callPropWithArity', callPropWithArity, args);
    });

    describe('callProp', function() {
      var callProp = object.callProp;

      it('callProp has correct arity', function() {
        expect(getRealArity(callProp)).to.equal(1);
      });

      it('Returned function has correct arity', function() {
        var fn = callProp('prop');

        expect(fn.length).to.equal(1);
      });

      it('Returned function has correct \'real\' arity', function() {
        var fn = callProp('prop');

        expect(getRealArity(fn)).to.equal(1);
      });

      it('Returned function calls prop on given object', function() {
        var obj = {called: false, calledProp: function() {this.called = true;}};
        var caller = callProp('calledProp');
        var result = caller(obj);

        expect(obj.called).to.be.true;
      });

      it('Returned function returns correct result when called', function() {
        var obj = {calledProp: function() {return [].slice.call(arguments);}};
        var obj2 = {calledProp: function() {return 42;}};
        var caller = callProp('calledProp');
        var result = caller.call(null, obj);
        var result2 = caller.call(null, obj2);

        expect(result).to.deep.equal([]);
        expect(result2).to.equal(42);
      });
    });

    describe('hasOwnProperty', function() {
      var hasOwnProperty = object.hasOwnProperty;

      it('hasOwnProperty has correct arity', function() {
        expect(getRealArity(hasOwnProperty)).to.equal(2);
      });

      it('Wraps Object.prototype.hasOwnProperty', function() {
        // Temporary monkey-patch
        var original = Object.prototype.hasOwnProperty;
        var fn = function() {fn.called = true;};
        fn.called = false;
        Object.prototype.hasOwnProperty = fn;
        var obj = {funkier: 1};
        hasOwnProperty('funkier', obj);

        expect(fn.called).to.be.true;
        Object.prototype.hasOwnProperty = original;
      });

      it('Works correctly (1)', function() {
        var obj = {funkier: 1};
        var result = hasOwnProperty('funkier', obj);

        expect(result).to.be.true;
      });

      it('Works correctly (2)', function() {
        var Constructor = function() {};
        Constructor.prototype.funkier = 1;
        var obj = new Constructor();
        var result = hasOwnProperty('funkier', obj);

        expect(result).to.be.false;
      });

      testCurriedFunction('hasOwnProperty', hasOwnProperty, ['funkier', {funkier: 1}]);
    });

    describe('hasProperty', function() {
      var hasProperty = object.hasProperty;

      it('hasProperty has correct arity', function() {
        expect(getRealArity(hasProperty)).to.equal(2);
      });

      it('Works correctly (1)', function() {
        var obj = {funkier: 1};
        var result = hasProperty('funkier', obj);

        expect(result).to.be.true;
      });

      it('Works correctly (2)', function() {
        var Constructor = function() {};
        Constructor.prototype.funkier = 1;
        var obj = new Constructor();
        var result = hasProperty('funkier', obj);

        expect(result).to.be.true;
      });

      testCurriedFunction('hasProperty', hasProperty, ['funkier', {funkier: 1}]);
    });

    describe('instanceOf', function() {
      var instanceOf = object.instanceOf;

      it('instanceOf has correct arity', function() {
        expect(getRealArity(instanceOf)).to.equal(2);
      });

      it('Works correctly (1)', function() {
        expect(instanceOf(Object, {})).to.be.true;
      });

      it('Works correctly (2)', function() {
        var Constructor = function() {};
        var obj = new Constructor();

        expect(instanceOf(Constructor, obj)).to.be.true;
      });

      it('Works correctly (3)', function() {
        var Constructor = function() {};
        var Proto = function() {};
        Constructor.prototype = new Proto();
        var obj = new Constructor();

        expect(instanceOf(Proto, obj)).to.be.true;
      });

      it('Works correctly (4)', function() {
        var Constructor = function() {};
        var Proto = function() {};
        var obj = new Constructor();

        expect(instanceOf(Proto, obj)).to.be.false;
      });

      testCurriedFunction('instanceOf', instanceOf, [Object, {}]);
    });

    describe('isPrototypeOf', function() {
      var isPrototypeOf = object.isPrototypeOf;

      it('isPrototypeOf has correct arity', function() {
        expect(getRealArity(isPrototypeOf)).to.equal(2);
      });

      it('Wraps Object.prototype.isPrototypeOf', function() {
        // Temporary monkey-patch
        var original = Object.prototype.isPrototypeOf;
        var fn = function() {fn.called = true;};
        fn.called = false;
        Object.prototype.isPrototypeOf = fn;
        var obj = {funkier: 1};
        isPrototypeOf({}, obj);

        expect(fn.called).to.be.true;
        Object.prototype.isPrototypeOf = original;
      });

      it('Calls Object.prototype.isPrototypeOf on correct object', function() {
        // Temporary monkey-patch
        var original = Object.prototype.isPrototypeOf;
        var fn = function() {fn.thisObj = this;};
        fn.thisObj = null;
        Object.prototype.isPrototypeOf = fn;
        var protoCheck = {};
        var obj = {funkier: 1};
        isPrototypeOf(protoCheck, obj);

        expect(fn.thisObj).to.equal(protoCheck);
        Object.prototype.isPrototypeOf = original;
      });

      it('Works correctly (1)', function() {
        expect(isPrototypeOf(Object.prototype, {})).to.be.true;
      });

      it('Works correctly (2)', function() {
        var Constructor = function() {};
        var obj = new Constructor();

        expect(isPrototypeOf(Constructor.prototype, obj)).to.be.true;
      });

      it('Works correctly (3)', function() {
        var Constructor = function() {};
        var Proto = function() {};
        Constructor.prototype = new Proto();
        var obj = new Constructor();

        expect(isPrototypeOf(Proto.prototype, obj)).to.be.true;
      });

      it('Works correctly (4)', function() {
        var Constructor = function() {};
        var Proto = function() {};
        var obj = new Constructor();

        expect(isPrototypeOf(Proto.prototype, obj)).to.be.false;
      });

      testCurriedFunction('isPrototypeOf', isPrototypeOf, [Object.prototype, {}]);
    });

    describe('createObject', function() {
      var createObject = object.createObject;
      var isPrototypeOf = object.isPrototypeOf;
      var hasOwnProperty = object.hasOwnProperty;

      it('createObject has correct arity', function() {
        expect(getRealArity(createObject)).to.equal(1);
      });

      it('Returns an object', function() {
        var obj = {funkier: 1};
        var result = createObject(obj);

        expect(result).to.be.a('object');
      });

      it('Works correctly', function() {
        var obj = {funkier: 1};
        var result = createObject(obj);

        expect(isPrototypeOf(obj, result)).to.be.true;
      });

      it('Ignores superfluous parameters', function() {
        var obj = {funkier: 1};
        var result = createObject(obj,
                      {prop1: {configurable: false, enumerable: false, writable: false, value: 42}});

        expect(hasOwnProperty('prop1', result)).to.be.false;
      });
    });

    describe('createObjectWithProps', function() {
      var createObjectWithProps = object.createObjectWithProps;
      var isPrototypeOf = object.isPrototypeOf;
      var hasOwnProperty = object.hasOwnProperty;
      var descriptor = {prop1: {configurable: false, enumerable: false, writable: false, value: 42}};

      it('createObjectWithProps has correct arity', function() {
        expect(getRealArity(createObjectWithProps)).to.equal(2);
      });

      it('Returns an object', function() {
        var obj = {funkier: 1};
        var result = createObjectWithProps(obj, descriptor);

        expect(result).to.be.a('object');
      });

      it('Works correctly (1)', function() {
        var obj = {funkier: 1};
        var result = createObjectWithProps(obj, descriptor);

        expect(isPrototypeOf(obj, result)).to.be.true;
      });

      it('Works correctly (2)', function() {
        var obj = {funkier: 1};
        var result = createObjectWithProps(obj, descriptor);

        expect(hasOwnProperty('prop1', result)).to.be.true;
      });

      it('Works correctly (3)', function() {
        var obj = {funkier: 1};
        var result = createObjectWithProps(obj, descriptor);

        var descriptorProps = Object.keys(descriptor.prop1);
        var actualDescriptor = Object.getOwnPropertyDescriptor(result, 'prop1');
        var leftComparison = descriptorProps.every(function(p) {
          return (p in actualDescriptor) && descriptor.prop1[p] === actualDescriptor[p];
        });
        var actualDescriptorProps = Object.keys(actualDescriptor);
        var rightComparison = actualDescriptorProps.every(function(p) {
          return (p in descriptor.prop1) && descriptor.prop1[p] === actualDescriptor[p];
        });

        expect(leftComparison && rightComparison).to.be.true;
      });

      // We cannot use testCurriedFunction, as createObjectWithProps produces an object, which
      // will cause the equality check to fail

      it('createObjectWithProps is curried (1)', function() {
        expect(getRealArity(createObjectWithProps({}))).to.equal(1);
      });

      it('createObjectWithProps is curried (2)', function() {
        var obj = {funkier: 1};
        var result = createObjectWithProps(obj)(descriptor);

        expect(result).to.be.a('object');
      });

      it('createObjectWithProps is curried (3)', function() {
        var obj = {funkier: 1};
        var result = createObjectWithProps(obj)(descriptor);

        expect(isPrototypeOf(obj, result)).to.be.true;
      });

      it('createObjectWithProps is curried (4)', function() {
        var obj = {funkier: 1};
        var result = createObjectWithProps(obj)(descriptor);

        expect(hasOwnProperty('prop1', result)).to.be.true;
      });

      it('createObjectWithProps is curried (5)', function() {
        var obj = {funkier: 1};
        var result = createObjectWithProps(obj)(descriptor);

        var descriptorProps = Object.keys(descriptor.prop1);
        var actualDescriptor = Object.getOwnPropertyDescriptor(result, 'prop1');
        var leftComparison = descriptorProps.every(function(p) {
          return (p in actualDescriptor) && descriptor.prop1[p] === actualDescriptor[p];
        });
        var actualDescriptorProps = Object.keys(actualDescriptor);
        var rightComparison = actualDescriptorProps.every(function(p) {
          return (p in descriptor.prop1) && descriptor.prop1[p] === actualDescriptor[p];
        });

        expect(leftComparison && rightComparison).to.be.true;
      });
    });
  };

  // AMD/CommonJS foo: aim to allow running testsuite in browser with require.js (TODO)
  if (typeof(define) === "function") {
    define(function(require, exports, module) {
      testFixture(require, exports, module);
    });
  } else {
    testFixture(require, exports, module);
  }
})();
<commit_msg>Refactor 'createObjectWithProps' tests<commit_after>(function() {
  "use strict";

  var testFixture = function(require, exports) {
    var chai = require('chai');
    var expect = chai.expect;

    var base = require('../base');
    var getRealArity = base.getRealArity;

    var object = require('../object');

    // Import utility functions
    var testUtils = require('./testUtils');
    var exportsProperty = testUtils.exportsProperty;
    var exportsFunction = testUtils.exportsFunction;
    var testCurriedFunction = testUtils.testCurriedFunction;

    describe('Object exports', function() {
      var expectedFunctions = ['callPropWithArity', 'callProp', 'hasOwnProperty',
                               'hasProperty', 'instanceOf', 'isPrototypeOf', 'createObject',
                               'createObjectWithProps'];

      // Automatically generate existence tests for each expected function
      expectedFunctions.forEach(function(f) {
        it('object.js exports \'' + f + '\' property', exportsProperty(object, f));
        it('\'' + f + '\' property of object.js is a function', exportsFunction(object, f));
      });
    });

    describe('callPropWithArity', function() {
      var callPropWithArity = object.callPropWithArity;

      it('callPropWithArity has correct \'real\' arity', function() {
        expect(getRealArity(callPropWithArity)).to.equal(2);
      });

      // Test generation
      var makeReturnedCurriedArityTest = function(i) {
        return function() {
          var fn = callPropWithArity('prop', i);

          expect(fn.length).to.equal(1);
        };
      };

      var makeReturnedArityTest = function(i) {
        return function() {
          var fn = callPropWithArity('prop', i);

          expect(getRealArity(fn)).to.equal(i + 1);
        };
      };

      var functionalityArgs = [1, true, null, function() {}, []];
      var makeCalledTest = function(i) {
        return function() {
          var args = functionalityArgs.slice(0, i);
          var obj = {called: false, calledProp: function() {this.called = true;}};
          var caller = callPropWithArity('calledProp', i);
          var result = caller.apply(null, args.concat([obj]));

          expect(obj.called).to.be.true;
        }
      };

      var makeReturnedValueTest = function(i) {
        return function() {
          var expected = functionalityArgs.slice(0, i);
          var obj = {calledProp: function() {return [].slice.call(arguments);}};
          var obj2 = {calledProp: function() {return 42;}};
          var caller = callPropWithArity('calledProp', i);
          var result = caller.apply(null, expected.concat([obj]));
          var result2 = caller.apply(null, expected.concat([obj2]));

          expect(result).to.deep.equal(expected);
          expect(result2).to.equal(42);
        };
      };

      for (var i = 0; i < 6; i++) {
        it('Returned function has correct arity for arity' + i,
           makeReturnedCurriedArityTest(i));

        it('Returned function has correct \'real\' arity' + i,
           makeReturnedArityTest(i));

        it('Returned function calls prop on given object' + i,
           makeCalledTest(i));

        it('Returned function returns correct result when called' + i,
           makeReturnedValueTest(i));

        // The returned function should be curried
        var testObj = {prop: function(x) {return x;}};
        var caller = callPropWithArity('prop', 1);
        testCurriedFunction('Returned function', caller, [2, testObj]);
      }

      // callPropWithArity should itself be curried
      var testObj = {property: function() {return 42;}};
      var args = {firstArgs: ['property', 0], thenArgs: [testObj]};
      testCurriedFunction('callPropWithArity', callPropWithArity, args);
    });

    describe('callProp', function() {
      var callProp = object.callProp;

      it('callProp has correct arity', function() {
        expect(getRealArity(callProp)).to.equal(1);
      });

      it('Returned function has correct arity', function() {
        var fn = callProp('prop');

        expect(fn.length).to.equal(1);
      });

      it('Returned function has correct \'real\' arity', function() {
        var fn = callProp('prop');

        expect(getRealArity(fn)).to.equal(1);
      });

      it('Returned function calls prop on given object', function() {
        var obj = {called: false, calledProp: function() {this.called = true;}};
        var caller = callProp('calledProp');
        var result = caller(obj);

        expect(obj.called).to.be.true;
      });

      it('Returned function returns correct result when called', function() {
        var obj = {calledProp: function() {return [].slice.call(arguments);}};
        var obj2 = {calledProp: function() {return 42;}};
        var caller = callProp('calledProp');
        var result = caller.call(null, obj);
        var result2 = caller.call(null, obj2);

        expect(result).to.deep.equal([]);
        expect(result2).to.equal(42);
      });
    });

    describe('hasOwnProperty', function() {
      var hasOwnProperty = object.hasOwnProperty;

      it('hasOwnProperty has correct arity', function() {
        expect(getRealArity(hasOwnProperty)).to.equal(2);
      });

      it('Wraps Object.prototype.hasOwnProperty', function() {
        // Temporary monkey-patch
        var original = Object.prototype.hasOwnProperty;
        var fn = function() {fn.called = true;};
        fn.called = false;
        Object.prototype.hasOwnProperty = fn;
        var obj = {funkier: 1};
        hasOwnProperty('funkier', obj);

        expect(fn.called).to.be.true;
        Object.prototype.hasOwnProperty = original;
      });

      it('Works correctly (1)', function() {
        var obj = {funkier: 1};
        var result = hasOwnProperty('funkier', obj);

        expect(result).to.be.true;
      });

      it('Works correctly (2)', function() {
        var Constructor = function() {};
        Constructor.prototype.funkier = 1;
        var obj = new Constructor();
        var result = hasOwnProperty('funkier', obj);

        expect(result).to.be.false;
      });

      testCurriedFunction('hasOwnProperty', hasOwnProperty, ['funkier', {funkier: 1}]);
    });

    describe('hasProperty', function() {
      var hasProperty = object.hasProperty;

      it('hasProperty has correct arity', function() {
        expect(getRealArity(hasProperty)).to.equal(2);
      });

      it('Works correctly (1)', function() {
        var obj = {funkier: 1};
        var result = hasProperty('funkier', obj);

        expect(result).to.be.true;
      });

      it('Works correctly (2)', function() {
        var Constructor = function() {};
        Constructor.prototype.funkier = 1;
        var obj = new Constructor();
        var result = hasProperty('funkier', obj);

        expect(result).to.be.true;
      });

      testCurriedFunction('hasProperty', hasProperty, ['funkier', {funkier: 1}]);
    });

    describe('instanceOf', function() {
      var instanceOf = object.instanceOf;

      it('instanceOf has correct arity', function() {
        expect(getRealArity(instanceOf)).to.equal(2);
      });

      it('Works correctly (1)', function() {
        expect(instanceOf(Object, {})).to.be.true;
      });

      it('Works correctly (2)', function() {
        var Constructor = function() {};
        var obj = new Constructor();

        expect(instanceOf(Constructor, obj)).to.be.true;
      });

      it('Works correctly (3)', function() {
        var Constructor = function() {};
        var Proto = function() {};
        Constructor.prototype = new Proto();
        var obj = new Constructor();

        expect(instanceOf(Proto, obj)).to.be.true;
      });

      it('Works correctly (4)', function() {
        var Constructor = function() {};
        var Proto = function() {};
        var obj = new Constructor();

        expect(instanceOf(Proto, obj)).to.be.false;
      });

      testCurriedFunction('instanceOf', instanceOf, [Object, {}]);
    });

    describe('isPrototypeOf', function() {
      var isPrototypeOf = object.isPrototypeOf;

      it('isPrototypeOf has correct arity', function() {
        expect(getRealArity(isPrototypeOf)).to.equal(2);
      });

      it('Wraps Object.prototype.isPrototypeOf', function() {
        // Temporary monkey-patch
        var original = Object.prototype.isPrototypeOf;
        var fn = function() {fn.called = true;};
        fn.called = false;
        Object.prototype.isPrototypeOf = fn;
        var obj = {funkier: 1};
        isPrototypeOf({}, obj);

        expect(fn.called).to.be.true;
        Object.prototype.isPrototypeOf = original;
      });

      it('Calls Object.prototype.isPrototypeOf on correct object', function() {
        // Temporary monkey-patch
        var original = Object.prototype.isPrototypeOf;
        var fn = function() {fn.thisObj = this;};
        fn.thisObj = null;
        Object.prototype.isPrototypeOf = fn;
        var protoCheck = {};
        var obj = {funkier: 1};
        isPrototypeOf(protoCheck, obj);

        expect(fn.thisObj).to.equal(protoCheck);
        Object.prototype.isPrototypeOf = original;
      });

      it('Works correctly (1)', function() {
        expect(isPrototypeOf(Object.prototype, {})).to.be.true;
      });

      it('Works correctly (2)', function() {
        var Constructor = function() {};
        var obj = new Constructor();

        expect(isPrototypeOf(Constructor.prototype, obj)).to.be.true;
      });

      it('Works correctly (3)', function() {
        var Constructor = function() {};
        var Proto = function() {};
        Constructor.prototype = new Proto();
        var obj = new Constructor();

        expect(isPrototypeOf(Proto.prototype, obj)).to.be.true;
      });

      it('Works correctly (4)', function() {
        var Constructor = function() {};
        var Proto = function() {};
        var obj = new Constructor();

        expect(isPrototypeOf(Proto.prototype, obj)).to.be.false;
      });

      testCurriedFunction('isPrototypeOf', isPrototypeOf, [Object.prototype, {}]);
    });

    describe('createObject', function() {
      var createObject = object.createObject;
      var isPrototypeOf = object.isPrototypeOf;
      var hasOwnProperty = object.hasOwnProperty;

      it('createObject has correct arity', function() {
        expect(getRealArity(createObject)).to.equal(1);
      });

      it('Returns an object', function() {
        var obj = {funkier: 1};
        var result = createObject(obj);

        expect(result).to.be.a('object');
      });

      it('Works correctly', function() {
        var obj = {funkier: 1};
        var result = createObject(obj);

        expect(isPrototypeOf(obj, result)).to.be.true;
      });

      it('Ignores superfluous parameters', function() {
        var obj = {funkier: 1};
        var result = createObject(obj,
                      {prop1: {configurable: false, enumerable: false, writable: false, value: 42}});

        expect(hasOwnProperty('prop1', result)).to.be.false;
      });
    });

    describe('createObjectWithProps', function() {
      var createObjectWithProps = object.createObjectWithProps;
      var isPrototypeOf = object.isPrototypeOf;
      var hasOwnProperty = object.hasOwnProperty;
      var descriptor = {prop1: {configurable: false, enumerable: false, writable: false, value: 42}};

      it('createObjectWithProps has correct arity', function() {
        expect(getRealArity(createObjectWithProps)).to.equal(2);
      });

      it('Returns an object', function() {
        var obj = {funkier: 1};
        var result = createObjectWithProps(obj, descriptor);

        expect(result).to.be.a('object');
      });

      it('Works correctly (1)', function() {
        var obj = {funkier: 1};
        var result = createObjectWithProps(obj, descriptor);

        expect(isPrototypeOf(obj, result)).to.be.true;
      });

      it('Works correctly (2)', function() {
        var obj = {funkier: 1};
        var result = createObjectWithProps(obj, descriptor);

        expect(hasOwnProperty('prop1', result)).to.be.true;
      });

      it('Works correctly (3)', function() {
        var obj = {funkier: 1};
        var result = createObjectWithProps(obj, descriptor);

        var descriptorProps = Object.keys(descriptor.prop1);
        var actualDescriptor = Object.getOwnPropertyDescriptor(result, 'prop1');
        var leftComparison = descriptorProps.every(function(p) {
          return (p in actualDescriptor) && descriptor.prop1[p] === actualDescriptor[p];
        });
        var actualDescriptorProps = Object.keys(actualDescriptor);
        var rightComparison = actualDescriptorProps.every(function(p) {
          return (p in descriptor.prop1) && descriptor.prop1[p] === actualDescriptor[p];
        });

        expect(leftComparison && rightComparison).to.be.true;
      });

      testCurriedFunction('createObjectWithProps', createObjectWithProps, [{}, descriptor]);
    });
  };

  // AMD/CommonJS foo: aim to allow running testsuite in browser with require.js (TODO)
  if (typeof(define) === "function") {
    define(function(require, exports, module) {
      testFixture(require, exports, module);
    });
  } else {
    testFixture(require, exports, module);
  }
})();
<|endoftext|>


<commit_before>window.cls || (window.cls = {});

window.cls.NewScript = function(message)
{
  const
  RUNTIME_ID = 0,
  SCRIPT_ID = 1,
  SCRIPT_TYPE = 2,
  SCRIPT_DATA = 3,
  URI = 4;

  this.runtime_id = message[RUNTIME_ID];
  this.script_id = message[SCRIPT_ID];
  this.script_type = message[SCRIPT_TYPE];
  this.script_data = message[SCRIPT_DATA] || '';
  this.uri = message[URI];
  this.breakpoints = {};
  this.breakpoint_states = [];
  this.line_pointer = {line: 0, state: 0};
  this.stop_ats = [];
  this.scroll_height = 0;
  this.scroll_width = 0;
};

window.cls.NewScript.BP_NONE = 0;
window.cls.NewScript.BP_DISABLED = 3;
window.cls.NewScript.BP_DISABLED_CONDITION = 6;
window.cls.NewScript.BP_ENABLED = 9;
window.cls.NewScript.BP_ENABLED_CONDITION = 12;
window.cls.NewScript.LINE_POINTER_TOP = 1;
window.cls.NewScript.LINE_POINTER = 2;

window.cls.NewScript.prototype = new function()
{
  /**
    * Searches the actual data.
    * Updates the script object with the following properties for all matches:
    *   - line_matches, a list of all matches in the source,
    *     the values are the lines numbers of a given match
    *   - line_offsets, a list of all matches in the source,
    *     the values are the character offset in the line of the match
    *   - match_cursor, pointing to the selected match
    *   _ match_length, the length of the search term
    */
  this.search_source = function(search_term, is_ignore_case, is_reg_exp)
  {
    if (is_ignore_case && !is_reg_exp)
    {
      search_term = search_term.toLowerCase();
    }
    if (is_reg_exp)
    {
      search_term = new RegExp(search_term, is_ignore_case ? 'ig' : 'g');
    }
    if (this.search_term != search_term ||
        this.is_ignore_case != is_ignore_case ||
        this.is_reg_exp != is_reg_exp)
    {
      if (!this.line_arr)
      {
        this.set_line_states();
      }
      this.search_term = search_term;
      this.is_ignore_case = is_ignore_case;
      this.is_reg_exp = is_reg_exp;
      this.line_matches = [];
      this.line_offsets = [];
      this.line_offsets_length = [];
      this.match_cursor = -1;
      this.match_length = search_term.length;
      if (!this.script_data_lower)
      {
        this.script_data_lower = this.script_data.toLowerCase();
      }
      if (search_term)
      {
        var pos = -1;
        var line_cur = 0;
        var index = 0;
        var line_arr_length = this.line_arr.length;
        var match = null;
        while (true)
        {
          if (is_reg_exp)
          {
            match = search_term.exec(this.script_data);
            pos = match ? match.index : -1;
          }
          else if(is_ignore_case)
          {
            pos = this.script_data_lower.indexOf(search_term, pos + 1);
          }
          else
          {
            pos = this.script_data.indexOf(search_term, pos + 1);
          }
          if (pos == -1)
          {
            break;
          }
          while (line_cur < line_arr_length && this.line_arr[line_cur] <= pos)
          {
            ++line_cur;
          }
          this.line_matches[this.line_matches.length] = line_cur;
          this.line_offsets[this.line_offsets.length] = pos - this.line_arr[line_cur - 1];
          if (is_reg_exp)
          {
            this.line_offsets_length[index++] = match[0].length
          }
        }
      }
    }
  };

  this.set_line_states = function()
  {
    this.line_arr = [];
    this.state_arr = [];
    var input = this.script_data, line_arr = this.line_arr, state_arr = this.state_arr;
    var cur_cur = -1;
    var line_cur = 0;
    var line_cur_prev = -1;
    var s_quote_cur = -2;
    var d_quote_cur = -2;
    var slash_cur = -2;
    var nl_cur = 0;
    var cr_cur = 0;

    var min_cur = 0;

    var s_quote_val = '\'';
    var d_quote_val = '"';
    var slash_val = '/';
    var NL = '\n';
    var CR = '\r';

    var eol = NL;
    // old mac end of lines
    if (/\r(?!\n)/.test(input))
    {
      eol = CR;
    }

    var line_count = 0;

    var temp_count = 0;

    var temp_char = '';

    var temp_type = '';

    var string = input;
    // states = default, s_quote, d_qute, slash
    var DEFAULT = 0, SINGLE_QUOTE = 1, DOUBLE_QUOTE = 2, REG_EXP = 3, COMMENT = 4;
    // lexer_states = default, s_quote, d_qute, slash
    var lex_state = 'DEFAULT'; // SINGLE_QUOTE; DOUBLE_QUOTE; SLASH
    var LEX_S_QUOTE = 1;
    var state = '';

    var get_min = Math.min;
    var get_max = Math.max;

    var handle_strings = function(ref_pos, ref_val)
    {
      // ensure that a string never exceeds the current
      // line if the newline is not escaped
      var temp_count = 0;
      var is_cr = 0;
      var nl_cur = string.indexOf(eol, ref_pos + 1);
      do
      {
        // newline was escaped
        if (temp_count && (nl_cur == ref_pos))
          nl_cur = string.indexOf(eol, nl_cur + 1);
        ref_pos = string.indexOf(ref_val, ref_pos + 1);
        if (nl_cur > -1 && nl_cur < ref_pos)
        {
          ref_pos = nl_cur;
          is_cr = (eol == NL && string[nl_cur - 1] == CR) ? 1 : 0;
        }
        temp_count = 0;
        while (string.charAt(ref_pos - temp_count - 1 - is_cr) == '\\')
          temp_count++;
      }
      while ((temp_count & 1) && ref_pos != -1);
      return ref_pos;
    };

    while( min_cur != -1 )
    {

      state = '';
      if( ( s_quote_cur != -1 ) && ( s_quote_cur <= cur_cur ) )
      {
        s_quote_cur = string.indexOf(s_quote_val, cur_cur + 1);
      }
      if( ( d_quote_cur != -1 ) && ( d_quote_cur <= cur_cur ) )
      {
        d_quote_cur = string.indexOf(d_quote_val, cur_cur + 1);
      }
      if( ( slash_cur != -1 ) && ( slash_cur <= cur_cur ) )
      {
        slash_cur = string.indexOf(slash_val, cur_cur + 1);
      }
      // get the minimum, but bigger then -1
      min_cur = get_max(s_quote_cur, d_quote_cur, slash_cur);
      if( s_quote_cur != -1 && s_quote_cur <= min_cur)
      {
        min_cur = s_quote_cur;
        state = 'SINGLE_QUOTE';
      }
      if( d_quote_cur != -1 && d_quote_cur <= min_cur )
      {
        min_cur = d_quote_cur;
        state = 'DOUBLE_QUOTE';
      }
      if( slash_cur != -1 && slash_cur <= min_cur )
      {
        min_cur = slash_cur;
        state = 'SLASH';
      }
      if( state )
      {

        while( line_cur <= min_cur )
        {
          line_arr[line_count++] = line_cur;
          if( ( line_cur = string.indexOf(eol, line_cur) + 1 ) == 0 )
          {
            if( line_arr[ line_arr.length - 1 ] < string.length )
            {
              line_arr[line_count] = string.length;
            }
            return;
          }
        }
        switch( state )
        {
          case 'SINGLE_QUOTE':
          {
            s_quote_cur = handle_strings(s_quote_cur, s_quote_val);
            if( s_quote_cur != -1 )
            {
              cur_cur = s_quote_cur;
              while( line_cur < cur_cur )
              {
                line_arr[line_count] = line_cur;
                state_arr[line_count++] = SINGLE_QUOTE;
                if( ( line_cur = string.indexOf(eol, line_cur) + 1 ) == 0 )
                {
                  if( line_arr[ line_arr.length - 1 ] < string.length )
                  {
                    line_arr[line_count] = string.length;
                  }
                  return;
                }
              }
            }
            continue;
          }
          case 'DOUBLE_QUOTE':
          {
            d_quote_cur = handle_strings(d_quote_cur, d_quote_val);
            if( d_quote_cur != -1 )
            {
              cur_cur = d_quote_cur;
              while( line_cur < cur_cur )
              {
                line_arr[line_count] = line_cur;
                state_arr[line_count++] = DOUBLE_QUOTE;
                if( ( line_cur = string.indexOf(eol, line_cur) + 1 ) == 0 )
                {
                  if( line_arr[ line_arr.length - 1 ] < string.length )
                  {
                    line_arr[line_count] = string.length;
                  }
                  return;
                }
              }
            }

            continue;
          }
          case 'SLASH':
          {
            switch(string.charAt(slash_cur+1))
            {
              case '/':
              {
                cur_cur = string.indexOf(eol, slash_cur+2);
                while( line_cur < cur_cur )
                {
                  line_arr[line_count++] = line_cur;
                  if( ( line_cur = string.indexOf(eol, line_cur) + 1 ) == 0 )
                  {
                    if( line_arr[ line_arr.length - 1 ] < string.length )
                    {
                      line_arr[line_count] = string.length;
                    }
                    return;
                  }
                }
                continue;
              }
              case '*':
              {
                do
                {
                  slash_cur = string.indexOf('*', slash_cur + 1);
                  temp_char = string.charAt(slash_cur + 1);
                }
                while ( slash_cur != -1 && temp_char && temp_char != '/');
                if( slash_cur != -1 )
                {
                  cur_cur = slash_cur+1;
                  while (line_cur < cur_cur)
                  {
                    line_arr[line_count] = line_cur;
                    state_arr[line_count++] = COMMENT;

                    if ((line_cur = string.indexOf(eol, line_cur) + 1) == 0)
                    {
                      if (line_arr[ line_arr.length - 1 ] < string.length)
                      {
                        line_arr[line_count] = string.length;
                      }
                      return;
                    }
                  }
                }
                continue;
              }
              default:
              {
                temp_count = 1;
                do
                {
                  temp_char = string.charAt(slash_cur-temp_count);
                  temp_count++;
                }
                while ( temp_char == ' ' && ( slash_cur - temp_count > 0 ) );
                switch(temp_char)
                {
                  case '=':
                  case '(':
                  case '[':
                  case ':':
                  case ',':
                  case '!':
                  {
                    temp_type = 'REG_EXP';
                    break;
                  }
                  case '&':
                  case '|':
                  {
                    if(string.charAt(slash_cur-temp_count) == temp_char)
                    {
                      temp_type = 'REG_EXP';
                      break;
                    }
                  }
                  default:
                  {
                    temp_type = '';
                  }
                }
                if(temp_type == 'REG_EXP')
                {
                  do
                  {
                    slash_cur = string.indexOf(slash_val, slash_cur + 1);
                    temp_count = 0;
                    while( string.charAt( slash_cur - temp_count - 1 )=='\\' )
                    {
                      temp_count++;
                    }
                  }
                  while ( ( temp_count&1 ) && slash_cur != -1 );
                  if( slash_cur != -1 )
                  {
                    cur_cur = slash_cur;
                    while( line_cur < cur_cur )
                    {
                      line_arr[line_count] = line_cur;
                      state_arr[line_count++] = REG_EXP;
                      if( ( line_cur = string.indexOf(eol, line_cur) + 1 ) == 0 )
                      {
                        if( line_arr[ line_arr.length - 1 ] < string.length )
                        {
                          line_arr[line_count] = string.length;
                        }
                        return;
                      }
                    }
                  }
                  continue;
                }
                else // should be a division
                {
                  cur_cur = slash_cur;
                  continue;
                }
              }
            }
          }
        }
      }
      else
      {
        if( !line_cur && !line_arr.length )
        {
          line_cur = string.indexOf(eol, line_cur) + 1 ;
          if( line_cur  || string.length )
          {
            line_arr[line_count++] = 0;
          }
        }
        while( line_cur )
        {
          line_arr[line_count++] = line_cur;
          line_cur = string.indexOf(eol, line_cur) + 1;
        }
        if( line_arr[ line_arr.length - 1 ] < string.length )
        {
          line_arr[line_count] = string.length;
        }

        return;
      }
    }
  }
}<commit_msg>Search with reg exp and ignore case.<commit_after>window.cls || (window.cls = {});

window.cls.NewScript = function(message)
{
  const
  RUNTIME_ID = 0,
  SCRIPT_ID = 1,
  SCRIPT_TYPE = 2,
  SCRIPT_DATA = 3,
  URI = 4;

  this.runtime_id = message[RUNTIME_ID];
  this.script_id = message[SCRIPT_ID];
  this.script_type = message[SCRIPT_TYPE];
  this.script_data = message[SCRIPT_DATA] || '';
  this.uri = message[URI];
  this.breakpoints = {};
  this.breakpoint_states = [];
  this.line_pointer = {line: 0, state: 0};
  this.stop_ats = [];
  this.scroll_height = 0;
  this.scroll_width = 0;
};

window.cls.NewScript.BP_NONE = 0;
window.cls.NewScript.BP_DISABLED = 3;
window.cls.NewScript.BP_DISABLED_CONDITION = 6;
window.cls.NewScript.BP_ENABLED = 9;
window.cls.NewScript.BP_ENABLED_CONDITION = 12;
window.cls.NewScript.LINE_POINTER_TOP = 1;
window.cls.NewScript.LINE_POINTER = 2;

window.cls.NewScript.prototype = new function()
{
  /**
    * Searches the actual data.
    * Updates the script object with the following properties for all matches:
    *   - line_matches, a list of all matches in the source,
    *     the values are the lines numbers of a given match
    *   - line_offsets, a list of all matches in the source,
    *     the values are the character offset in the line of the match
    *   - match_cursor, pointing to the selected match
    *   _ match_length, the length of the search term
    */
  this.search_source = function(search_term, is_ignore_case, is_reg_exp)
  {
    if (is_ignore_case && !is_reg_exp)
    {
      search_term = search_term.toLowerCase();
    }
    if (is_reg_exp)
    {
      search_term = new RegExp(search_term, is_ignore_case ? 'ig' : 'g');
    }
    if (this.search_term != search_term ||
        this.is_ignore_case != is_ignore_case ||
        this.is_reg_exp != is_reg_exp)
    {
      if (!this.line_arr)
      {
        this.set_line_states();
      }
      this.search_term = search_term;
      this.is_ignore_case = is_ignore_case;
      this.is_reg_exp = is_reg_exp;
      this.line_matches = [];
      this.line_offsets = [];
      this.line_offsets_length = [];
      this.match_cursor = -1;
      this.match_length = search_term.length;
      if (!this.script_data_lower)
      {
        this.script_data_lower = this.script_data.toLowerCase();
      }
      if (search_term)
      {
        var pos = -1;
        var line_cur = 0;
        var index = 0;
        var line_arr_length = this.line_arr.length;
        var match = null;
        while (true)
        {
          if (is_reg_exp)
          {
            match = search_term.exec(this.script_data);
            pos = match ? match.index : -1;
          }
          else if(is_ignore_case)
          {
            pos = this.script_data_lower.indexOf(search_term, pos + 1);
          }
          else
          {
            pos = this.script_data.indexOf(search_term, pos + 1);
          }
          if (pos == -1)
          {
            break;
          }
          while (line_cur < line_arr_length && this.line_arr[line_cur] <= pos)
          {
            ++line_cur;
          }
          this.line_matches[index] = line_cur;
          this.line_offsets[index] = pos - this.line_arr[line_cur - 1];
          if (is_reg_exp)
          {
            this.line_offsets_length[index] = match[0].length
          }
          index++;
        }
      }
    }
  };

  this.set_line_states = function()
  {
    this.line_arr = [];
    this.state_arr = [];
    var input = this.script_data, line_arr = this.line_arr, state_arr = this.state_arr;
    var cur_cur = -1;
    var line_cur = 0;
    var line_cur_prev = -1;
    var s_quote_cur = -2;
    var d_quote_cur = -2;
    var slash_cur = -2;
    var nl_cur = 0;
    var cr_cur = 0;

    var min_cur = 0;

    var s_quote_val = '\'';
    var d_quote_val = '"';
    var slash_val = '/';
    var NL = '\n';
    var CR = '\r';

    var eol = NL;
    // old mac end of lines
    if (/\r(?!\n)/.test(input))
    {
      eol = CR;
    }

    var line_count = 0;

    var temp_count = 0;

    var temp_char = '';

    var temp_type = '';

    var string = input;
    // states = default, s_quote, d_qute, slash
    var DEFAULT = 0, SINGLE_QUOTE = 1, DOUBLE_QUOTE = 2, REG_EXP = 3, COMMENT = 4;
    // lexer_states = default, s_quote, d_qute, slash
    var lex_state = 'DEFAULT'; // SINGLE_QUOTE; DOUBLE_QUOTE; SLASH
    var LEX_S_QUOTE = 1;
    var state = '';

    var get_min = Math.min;
    var get_max = Math.max;

    var handle_strings = function(ref_pos, ref_val)
    {
      // ensure that a string never exceeds the current
      // line if the newline is not escaped
      var temp_count = 0;
      var is_cr = 0;
      var nl_cur = string.indexOf(eol, ref_pos + 1);
      do
      {
        // newline was escaped
        if (temp_count && (nl_cur == ref_pos))
          nl_cur = string.indexOf(eol, nl_cur + 1);
        ref_pos = string.indexOf(ref_val, ref_pos + 1);
        if (nl_cur > -1 && nl_cur < ref_pos)
        {
          ref_pos = nl_cur;
          is_cr = (eol == NL && string[nl_cur - 1] == CR) ? 1 : 0;
        }
        temp_count = 0;
        while (string.charAt(ref_pos - temp_count - 1 - is_cr) == '\\')
          temp_count++;
      }
      while ((temp_count & 1) && ref_pos != -1);
      return ref_pos;
    };

    while( min_cur != -1 )
    {

      state = '';
      if( ( s_quote_cur != -1 ) && ( s_quote_cur <= cur_cur ) )
      {
        s_quote_cur = string.indexOf(s_quote_val, cur_cur + 1);
      }
      if( ( d_quote_cur != -1 ) && ( d_quote_cur <= cur_cur ) )
      {
        d_quote_cur = string.indexOf(d_quote_val, cur_cur + 1);
      }
      if( ( slash_cur != -1 ) && ( slash_cur <= cur_cur ) )
      {
        slash_cur = string.indexOf(slash_val, cur_cur + 1);
      }
      // get the minimum, but bigger then -1
      min_cur = get_max(s_quote_cur, d_quote_cur, slash_cur);
      if( s_quote_cur != -1 && s_quote_cur <= min_cur)
      {
        min_cur = s_quote_cur;
        state = 'SINGLE_QUOTE';
      }
      if( d_quote_cur != -1 && d_quote_cur <= min_cur )
      {
        min_cur = d_quote_cur;
        state = 'DOUBLE_QUOTE';
      }
      if( slash_cur != -1 && slash_cur <= min_cur )
      {
        min_cur = slash_cur;
        state = 'SLASH';
      }
      if( state )
      {

        while( line_cur <= min_cur )
        {
          line_arr[line_count++] = line_cur;
          if( ( line_cur = string.indexOf(eol, line_cur) + 1 ) == 0 )
          {
            if( line_arr[ line_arr.length - 1 ] < string.length )
            {
              line_arr[line_count] = string.length;
            }
            return;
          }
        }
        switch( state )
        {
          case 'SINGLE_QUOTE':
          {
            s_quote_cur = handle_strings(s_quote_cur, s_quote_val);
            if( s_quote_cur != -1 )
            {
              cur_cur = s_quote_cur;
              while( line_cur < cur_cur )
              {
                line_arr[line_count] = line_cur;
                state_arr[line_count++] = SINGLE_QUOTE;
                if( ( line_cur = string.indexOf(eol, line_cur) + 1 ) == 0 )
                {
                  if( line_arr[ line_arr.length - 1 ] < string.length )
                  {
                    line_arr[line_count] = string.length;
                  }
                  return;
                }
              }
            }
            continue;
          }
          case 'DOUBLE_QUOTE':
          {
            d_quote_cur = handle_strings(d_quote_cur, d_quote_val);
            if( d_quote_cur != -1 )
            {
              cur_cur = d_quote_cur;
              while( line_cur < cur_cur )
              {
                line_arr[line_count] = line_cur;
                state_arr[line_count++] = DOUBLE_QUOTE;
                if( ( line_cur = string.indexOf(eol, line_cur) + 1 ) == 0 )
                {
                  if( line_arr[ line_arr.length - 1 ] < string.length )
                  {
                    line_arr[line_count] = string.length;
                  }
                  return;
                }
              }
            }

            continue;
          }
          case 'SLASH':
          {
            switch(string.charAt(slash_cur+1))
            {
              case '/':
              {
                cur_cur = string.indexOf(eol, slash_cur+2);
                while( line_cur < cur_cur )
                {
                  line_arr[line_count++] = line_cur;
                  if( ( line_cur = string.indexOf(eol, line_cur) + 1 ) == 0 )
                  {
                    if( line_arr[ line_arr.length - 1 ] < string.length )
                    {
                      line_arr[line_count] = string.length;
                    }
                    return;
                  }
                }
                continue;
              }
              case '*':
              {
                do
                {
                  slash_cur = string.indexOf('*', slash_cur + 1);
                  temp_char = string.charAt(slash_cur + 1);
                }
                while ( slash_cur != -1 && temp_char && temp_char != '/');
                if( slash_cur != -1 )
                {
                  cur_cur = slash_cur+1;
                  while (line_cur < cur_cur)
                  {
                    line_arr[line_count] = line_cur;
                    state_arr[line_count++] = COMMENT;

                    if ((line_cur = string.indexOf(eol, line_cur) + 1) == 0)
                    {
                      if (line_arr[ line_arr.length - 1 ] < string.length)
                      {
                        line_arr[line_count] = string.length;
                      }
                      return;
                    }
                  }
                }
                continue;
              }
              default:
              {
                temp_count = 1;
                do
                {
                  temp_char = string.charAt(slash_cur-temp_count);
                  temp_count++;
                }
                while ( temp_char == ' ' && ( slash_cur - temp_count > 0 ) );
                switch(temp_char)
                {
                  case '=':
                  case '(':
                  case '[':
                  case ':':
                  case ',':
                  case '!':
                  {
                    temp_type = 'REG_EXP';
                    break;
                  }
                  case '&':
                  case '|':
                  {
                    if(string.charAt(slash_cur-temp_count) == temp_char)
                    {
                      temp_type = 'REG_EXP';
                      break;
                    }
                  }
                  default:
                  {
                    temp_type = '';
                  }
                }
                if(temp_type == 'REG_EXP')
                {
                  do
                  {
                    slash_cur = string.indexOf(slash_val, slash_cur + 1);
                    temp_count = 0;
                    while( string.charAt( slash_cur - temp_count - 1 )=='\\' )
                    {
                      temp_count++;
                    }
                  }
                  while ( ( temp_count&1 ) && slash_cur != -1 );
                  if( slash_cur != -1 )
                  {
                    cur_cur = slash_cur;
                    while( line_cur < cur_cur )
                    {
                      line_arr[line_count] = line_cur;
                      state_arr[line_count++] = REG_EXP;
                      if( ( line_cur = string.indexOf(eol, line_cur) + 1 ) == 0 )
                      {
                        if( line_arr[ line_arr.length - 1 ] < string.length )
                        {
                          line_arr[line_count] = string.length;
                        }
                        return;
                      }
                    }
                  }
                  continue;
                }
                else // should be a division
                {
                  cur_cur = slash_cur;
                  continue;
                }
              }
            }
          }
        }
      }
      else
      {
        if( !line_cur && !line_arr.length )
        {
          line_cur = string.indexOf(eol, line_cur) + 1 ;
          if( line_cur  || string.length )
          {
            line_arr[line_count++] = 0;
          }
        }
        while( line_cur )
        {
          line_arr[line_count++] = line_cur;
          line_cur = string.indexOf(eol, line_cur) + 1;
        }
        if( line_arr[ line_arr.length - 1 ] < string.length )
        {
          line_arr[line_count] = string.length;
        }

        return;
      }
    }
  }
}<|endoftext|>


<commit_before>/****************************************************/
/*         IOServer - v0.1.2                        */
/*                                                  */
/*         Damn simple socket.io server             */
/****************************************************/
/*             -    Copyright 2014    -             */
/*                                                  */
/*   License: Apache v 2.0                          */
/*   @Author: Ben Mz                                */
/*   @Email: x62en (at) users.noreply.github.com    */
/*                                                  */
/****************************************************/

(function() {
  var HOST, IOServer, PORT, Server;

  Server = require('socket.io');

  PORT = 8080;

  HOST = 'localhost';

  module.exports = IOServer = (function() {
    function IOServer(_arg) {
      var host, login, port, verbose, _ref;
      _ref = _arg != null ? _arg : {}, host = _ref.host, port = _ref.port, login = _ref.login, verbose = _ref.verbose;
      this.host = host != null ? host : HOST;
      this.port = port != null ? port : PORT;
      this.login = login != null ? login : null;
      this.verbose = verbose != null ? verbose : false;
      this.service_list = {};
      this.method_list = {};
    }

    IOServer.prototype.addService = function(_arg) {
      var name, service, _ref;
      _ref = _arg != null ? _arg : {}, name = _ref.name, service = _ref.service;
      if ((name != null) && name.length > 2) {
        this.service_list[name] = new service();
        return this._dumpMethods(name);
      } else {
        return console.error("#[!] Service name MUST be longer than 2 characters");
      }
    };

    IOServer.prototype.start = function() {
      var date, ns, service, service_name, _ref;
      date = this._now();
      if (this.verbose) {
        console.log("###################### " + date + " #############################");
        console.log("#[+] Starting server on port: " + this.port + " ...");
      }
      this.io = Server.listen(this.port);
      ns = {};
      _ref = this.service_list;
      for (service_name in _ref) {
        service = _ref[service_name];
        if (this.login != null) {
          ns[service_name] = this.io.of("/" + this.login + "/" + service_name);
        } else {
          ns[service_name] = this.io.of("/" + service_name);
        }
        if (this.verbose) {
          console.log("#[+] service " + service_name + " registered...");
        }
        ns[service_name].on('connection', this.handleEvents(ns[service_name], service_name));
      }
      if ((this.channel_list != null) && this.channel_list.length > 0) {
        return io.sockets.on('connection', this.handleEvents(io.sockets, 'global'));
      }
    };

    IOServer.prototype.handleEvents = function(ns, service_name) {
      return (function(_this) {
        return function(socket) {
          var action, index, _ref, _results;
          if (_this.verbose) {
            console.log("#[+] received connection for service " + service_name);
          }
          _ref = _this.method_list[service_name];
          _results = [];
          for (index in _ref) {
            action = _ref[index];
            if (action.substring(0, 1) === '_') {
              continue;
            }
            if (action === 'constructor') {
              continue;
            }
            if (_this.verbose) {
              console.log("#[+] method " + action + " of " + service_name + " listening...");
            }
            _results.push(socket.on(action, _this.handleCallback({
              service: service_name,
              method: action,
              socket: socket,
              namespace: ns
            })));
          }
          return _results;
        };
      })(this);
    };

    IOServer.prototype.handleCallback = function(_arg) {
      var method, namespace, service, socket, _ref;
      _ref = _arg != null ? _arg : {}, service = _ref.service, method = _ref.method, socket = _ref.socket, namespace = _ref.namespace;
      return (function(_this) {
        return function(data) {
          if (_this.verbose) {
            console.log("#[+] call method " + method + " of service " + service);
          }
          return _this.service_list[service][method](data, socket);
        };
      })(this);
    };

    IOServer.prototype.interact = function(_arg) {
      var data, method, room, service, _ref;
      _ref = _arg != null ? _arg : {}, service = _ref.service, room = _ref.room, method = _ref.method, data = _ref.data;
      return this._findClientsSocket({
        room: room,
        service: service,
        cb: (function(_this) {
          return function(connectedSockets) {
            var i, socket, _results;
            if (connectedSockets != null) {
              _results = [];
              for (i in connectedSockets) {
                socket = connectedSockets[i];
                if (socket != null) {
                  _results.push(socket.emit(method, data));
                } else {
                  _results.push(void 0);
                }
              }
              return _results;
            }
          };
        })(this)
      });
    };

    IOServer.prototype._dumpMethods = function(name) {
      var k, names, s;
      this.method_list[name] = [];
      s = this.method_list[name].prototype;
      while (k) {
        names = Object.getOwnPropertyNames(k);
        this.method_list[name] = this.method_list[name].concat(names);
        k = Object.getPrototypeOf(k);
        if (!Object.getPrototypeOf(k)) {
          break;
        }
      }
      return this.method_list[name].unique().sort();
    };

    IOServer.prototype._findClientsSocket = function(_arg) {
      var cb, i, id, index, ns, res, room, service, _ref, _ref1;
      _ref = _arg != null ? _arg : {}, service = _ref.service, room = _ref.room, cb = _ref.cb;
      res = [];
      ns = this.io.of(service || "/");
      if (ns) {
        _ref1 = ns.connected;
        for (id in _ref1) {
          i = _ref1[id];
          if ((room != null) && room.length > 0) {
            index = ns.connected[id].rooms.indexOf(room);
            if (index !== -1) {
              res.push(ns.connected[id]);
            }
          } else {
            res.push(ns.connected[id]);
          }
        }
      }
      return cb(res);
    };

    IOServer.prototype._now = function() {
      var d, day, hours, minutes, month, seconds, year;
      d = new Date();
      day = d.getDate();
      month = d.getMonth();
      year = d.getFullYear();
      hours = d.getHours();
      minutes = d.getMinutes();
      seconds = d.getSeconds();
      hours = hours < 10 ? "0" + hours : "" + hours;
      minutes = minutes < 10 ? ":0" + minutes : ":" + minutes;
      seconds = seconds < 10 ? ":0" + seconds : ":" + seconds;
      return "" + day + "/" + month + "/" + year + " - " + hours + minutes + seconds;
    };

    return IOServer;

  })();

}).call(this);
<commit_msg>Add _unique function<commit_after>/****************************************************/
/*         IOServer - v0.1.4                        */
/*                                                  */
/*         Damn simple socket.io server             */
/****************************************************/
/*             -    Copyright 2014    -             */
/*                                                  */
/*   License: Apache v 2.0                          */
/*   @Author: Ben Mz                                */
/*   @Email: x62en (at) users.noreply.github.com    */
/*                                                  */
/****************************************************/

(function() {
  var HOST, IOServer, PORT, Server;

  Server = require('socket.io');

  PORT = 8080;

  HOST = 'localhost';

  module.exports = IOServer = (function() {
    function IOServer(_arg) {
      var host, login, port, verbose, _ref;
      _ref = _arg != null ? _arg : {}, host = _ref.host, port = _ref.port, login = _ref.login, verbose = _ref.verbose;
      this.host = host != null ? host : HOST;
      this.port = port != null ? port : PORT;
      this.login = login != null ? login : null;
      this.verbose = verbose != null ? verbose : false;
      this.service_list = {};
      this.method_list = {};
    }

    IOServer.prototype.addService = function(_arg) {
      var name, service, _ref;
      _ref = _arg != null ? _arg : {}, name = _ref.name, service = _ref.service;
      if ((name != null) && name.length > 2) {
        this.service_list[name] = new service();
        return this._dumpMethods(name);
      } else {
        return console.error("#[!] Service name MUST be longer than 2 characters");
      }
    };

    IOServer.prototype.start = function() {
      var date, ns, service, service_name, _ref;
      date = this._now();
      if (this.verbose) {
        console.log("###################### " + date + " #############################");
        console.log("#[+] Starting server on port: " + this.port + " ...");
      }
      this.io = Server.listen(this.port);
      ns = {};
      _ref = this.service_list;
      for (service_name in _ref) {
        service = _ref[service_name];
        if (this.login != null) {
          ns[service_name] = this.io.of("/" + this.login + "/" + service_name);
        } else {
          ns[service_name] = this.io.of("/" + service_name);
        }
        if (this.verbose) {
          console.log("#[+] service " + service_name + " registered...");
        }
        ns[service_name].on('connection', this.handleEvents(ns[service_name], service_name));
      }
      if ((this.channel_list != null) && this.channel_list.length > 0) {
        return io.sockets.on('connection', this.handleEvents(io.sockets, 'global'));
      }
    };

    IOServer.prototype.handleEvents = function(ns, service_name) {
      return (function(_this) {
        return function(socket) {
          var action, index, _ref, _results;
          if (_this.verbose) {
            console.log("#[+] received connection for service " + service_name);
          }
          _ref = _this.method_list[service_name];
          _results = [];
          for (index in _ref) {
            action = _ref[index];
            if (action.substring(0, 1) === '_') {
              continue;
            }
            if (action === 'constructor') {
              continue;
            }
            if (_this.verbose) {
              console.log("#[+] method " + action + " of " + service_name + " listening...");
            }
            _results.push(socket.on(action, _this.handleCallback({
              service: service_name,
              method: action,
              socket: socket,
              namespace: ns
            })));
          }
          return _results;
        };
      })(this);
    };

    IOServer.prototype.handleCallback = function(_arg) {
      var method, namespace, service, socket, _ref;
      _ref = _arg != null ? _arg : {}, service = _ref.service, method = _ref.method, socket = _ref.socket, namespace = _ref.namespace;
      return (function(_this) {
        return function(data) {
          if (_this.verbose) {
            console.log("#[+] call method " + method + " of service " + service);
          }
          return _this.service_list[service][method](data, socket);
        };
      })(this);
    };

    IOServer.prototype.interact = function(_arg) {
      var data, method, room, service, _ref;
      _ref = _arg != null ? _arg : {}, service = _ref.service, room = _ref.room, method = _ref.method, data = _ref.data;
      return this._findClientsSocket({
        room: room,
        service: service,
        cb: (function(_this) {
          return function(connectedSockets) {
            var i, socket, _results;
            if (connectedSockets != null) {
              _results = [];
              for (i in connectedSockets) {
                socket = connectedSockets[i];
                if (socket != null) {
                  _results.push(socket.emit(method, data));
                } else {
                  _results.push(void 0);
                }
              }
              return _results;
            }
          };
        })(this)
      });
    };

    IOServer.prototype._dumpMethods = function(name) {
      var k, names, s;
      this.method_list[name] = [];
      s = this.method_list[name].prototype;
      while (k) {
        names = Object.getOwnPropertyNames(k);
        this.method_list[name] = this.method_list[name].concat(names);
        k = Object.getPrototypeOf(k);
        if (!Object.getPrototypeOf(k)) {
          break;
        }
      }
      return this.method_list[name] = this._unique(this.method_list[name]).sort();
    };

    IOServer.prototype._unique = function(arr) {
      var hash, i, l, result;
      hash = {};
      result = [];
      i = 0;
      l = arr.length;
      while (i < l) {
        if (!hash.hasOwnProperty(arr[i])) {
          hash[arr[i]] = true;
          result.push(arr[i]);
        }
        ++i;
      }
      return result;
    };

    IOServer.prototype._findClientsSocket = function(_arg) {
      var cb, i, id, index, ns, res, room, service, _ref, _ref1;
      _ref = _arg != null ? _arg : {}, service = _ref.service, room = _ref.room, cb = _ref.cb;
      res = [];
      ns = this.io.of(service || "/");
      if (ns) {
        _ref1 = ns.connected;
        for (id in _ref1) {
          i = _ref1[id];
          if ((room != null) && room.length > 0) {
            index = ns.connected[id].rooms.indexOf(room);
            if (index !== -1) {
              res.push(ns.connected[id]);
            }
          } else {
            res.push(ns.connected[id]);
          }
        }
      }
      return cb(res);
    };

    IOServer.prototype._now = function() {
      var d, day, hours, minutes, month, seconds, year;
      d = new Date();
      day = d.getDate();
      month = d.getMonth();
      year = d.getFullYear();
      hours = d.getHours();
      minutes = d.getMinutes();
      seconds = d.getSeconds();
      hours = hours < 10 ? "0" + hours : "" + hours;
      minutes = minutes < 10 ? ":0" + minutes : ":" + minutes;
      seconds = seconds < 10 ? ":0" + seconds : ":" + seconds;
      return "" + day + "/" + month + "/" + year + " - " + hours + minutes + seconds;
    };

    return IOServer;

  })();

}).call(this);
<|endoftext|>


<commit_before>var app = require('../src/app');
var _ = require('underscore');
var url = require('url');
var passport = require('passport');
var mongoose = require('mongoose');

var GitHubStrategy = require('passport-github2').Strategy;
var FacebookStrategy = require('passport-facebook').Strategy;

var GITHUB_CLIENT_ID = app.config.github.client_id;
var GITHUB_CLIENT_SECRET = app.config.github.client_secret;

var FACEBOOK_APP_ID = app.config.facebook.client_id;
var FACEBOOK_APP_SECRET = app.config.facebook.client_secret;

module.exports = {

	loadPriority:  800,
	startPriority: 800,
	stopPriority:  800,

	initialize: function(api, next) {

		function findOrCreateUser(user, cb) {
			if (user.id) {
				user.uid = (user.authType ? user.authType + ':' : '') + user.id;

				return api.models.user.model.findOrCreate({
					id: user.id,
					uid: user.uid,
					email: user.email,
					authType: user.authType,
					profile: user
				}, cb);
			}

			console.log("Trying to load this thing...", user);

			api.models.user.model.findOne({ uid : user }, function(err, user) {
				api.log('Hello?');
				if (!err && !user) {
					console.log("Not found!");
					cb("User not found");
				}
				console.log("This is what i got", err);
				console.log(user);
				cb(err, user);
			});

		}

		var authenticationMiddleware = function(connection, actionTemplate, next) {
			connection.session = connection.rawConnection.req.session;
			connection.user = connection.session.passport.user;

			if (actionTemplate.authenticated === true) {
				if (!connection.user) {
					connection.error = "No access";
				}
				next(connection, true);
			} else {
				next(connection, true);
			}
		};

		api.actions.addPreProcessor(authenticationMiddleware);

		passport.use('github', new GitHubStrategy({
				clientID: GITHUB_CLIENT_ID,
				clientSecret: GITHUB_CLIENT_SECRET,
				callbackURL: "http://foos.beer/api/auth/github/callback"
			},
			function(accessToken, refreshToken, profile, done) {

				profile.authType = 'github';

				api.log('This is my user: ' + JSON.stringify(profile));
				findOrCreateUser(profile, function(err, user, created) {
					if (created) {
						api.log("Hey, I just created a user!");
					}
					return done(null, user);
				});
			}
		));

		passport.use('facebook', new FacebookStrategy({
				clientID: FACEBOOK_APP_ID,
				clientSecret: FACEBOOK_APP_SECRET,
				callbackURL: "http://foos.beer/api/auth/facebook/callback",
				enableProof: false
			},
			function(accessToken, refreshToken, profile, done) {
				profile.authType = 'facebook';
				profile.email = profile.emails[0].value;

				api.log('This is my user: ' + JSON.stringify(profile));
				findOrCreateUser(profile, function(err, user, created) {
					if (created) {
						api.log("Hey, I just created a user!", user);
					}
					return done(null, user);
				});
			}
		));

		passport.serializeUser(function (user, done) {
			api.log("passport.serializeUser user: "+(user.id||user));
			done(null, user);
			return;
			// Faking a connection object as the first argument for
			// the session's save method. In this case it only needs
			// the connection id so it's safe to leave sparse
			// console.session.save({id:user.connection_id}, user, function (err) {
			// 	done(err, user.connection_id);
			// });
		});

		passport.deserializeUser(function (user, done) {
			api.log("passport.deserializeUser user: "+(user.id||user));

			return findOrCreateUser(user, done);

			// Faking a connection object as the first argument for
			// the session's load method. In this case it only needs
			// the connection id so it's safe to leave sparse
			// console.session.load({id:connection_id}, function (err, user) {
			// 	api.log("deserialized User: "+JSON.stringify(user));
			// 	if (err) {
			// 		api.log("ERROR: "+err);
			// 	}
			// 	done(null, user);
			// });
		});

		app.connect.use(passport.initialize());
		app.connect.use(passport.session());

		app.connect.use('/api/auth/facebook',
			passport.authenticate('facebook', { scope: ['email'] })
		);

		app.connect.use('/api/auth/facebook/callback',
			passport.authenticate('facebook')
		);

		app.connect.use('/api/auth/github',
			passport.authenticate('github', { scope: ['user:email'] })
		);

		app.connect.use('/api/auth/github/callback',
			passport.authenticate('github')
		);

		api.passport = passport;

		next();
	}
};
<commit_msg>Tweaks to session flow<commit_after>var app = require('../src/app');
var _ = require('underscore');
var url = require('url');
var passport = require('passport');
var mongoose = require('mongoose');

var GitHubStrategy = require('passport-github2').Strategy;
var FacebookStrategy = require('passport-facebook').Strategy;

var GITHUB_CLIENT_ID = app.config.github.client_id;
var GITHUB_CLIENT_SECRET = app.config.github.client_secret;

var FACEBOOK_APP_ID = app.config.facebook.client_id;
var FACEBOOK_APP_SECRET = app.config.facebook.client_secret;

module.exports = {

	loadPriority:  800,
	startPriority: 800,
	stopPriority:  800,

	initialize: function(api, next) {

		function findOrCreateUser(user, cb) {
			if (user.id) {
				user.uid = (user.authType ? user.authType + ':' : '') + user.id;

				return api.models.user.model.findOrCreate({
					id: user.id,
					uid: user.uid,
					email: user.email,
					authType: user.authType,
					profile: user
				}, cb);
			}

			console.log("Trying to load this thing...", user);

			api.models.user.model.findOne({ uid : user }, function(err, user) {
				api.log('Hello?');
				if (!err && !user) {
					console.log("Not found!");
					cb("User not found");
				}
				console.log("This is what i got", err);
				console.log(user);
				cb(err, user);
			});

		}

		var authenticationMiddleware = function(connection, actionTemplate, next) {
			connection.session = connection.rawConnection.req.session;
			connection.user = connection.session.passport.user;

			if (actionTemplate.authenticated === true) {
				if (!connection.user) {
					connection.error = "No access";
				}
				next(connection, true);
			} else {
				next(connection, true);
			}
		};

		api.actions.addPreProcessor(authenticationMiddleware);

		passport.use('github', new GitHubStrategy({
				clientID: GITHUB_CLIENT_ID,
				clientSecret: GITHUB_CLIENT_SECRET,
				callbackURL: "http://foos.beer/api/auth/github/callback"
			},
			function(accessToken, refreshToken, profile, done) {

				profile.authType = 'github';

				api.log('This is my user: ' + JSON.stringify(profile));
				findOrCreateUser(profile, function(err, user, created) {
					if (created) {
						api.log("Hey, I just created a user!");
					}
					return done(null, user);
				});
			}
		));

		passport.use('facebook', new FacebookStrategy({
				clientID: FACEBOOK_APP_ID,
				clientSecret: FACEBOOK_APP_SECRET,
				callbackURL: "http://foos.beer/api/auth/facebook/callback",
				enableProof: false
			},
			function(accessToken, refreshToken, profile, done) {
				profile.authType = 'facebook';
				profile.email = profile.emails[0].value;

				api.log('This is my user: ' + JSON.stringify(profile));
				findOrCreateUser(profile, function(err, user, created) {
					if (created) {
						api.log("Hey, I just created a user!", user);
					}
					return done(null, user);
				});
			}
		));

		passport.serializeUser(function (user, done) {
			api.log("passport.serializeUser user: "+(user.id||user));
			return findOrCreateUser(user, function(err, user) {
				done(err, user.uid);
			});

			// Faking a connection object as the first argument for
			// the session's save method. In this case it only needs
			// the connection id so it's safe to leave sparse
			// console.session.save({id:user.connection_id}, user, function (err) {
			// 	done(err, user.connection_id);
			// });
		});

		passport.deserializeUser(function (uid, done) {
			api.log("passport.deserializeUser user: "+(uid));

			api.mongodb.user.findOne({uid: uid}, function(err, user) {
				api.log("I found this user..." + JSON.stringify(user));
				done(err, user);
			});

			// return findOrCreateUser(user, done);

			// Faking a connection object as the first argument for
			// the session's load method. In this case it only needs
			// the connection id so it's safe to leave sparse
			// console.session.load({id:connection_id}, function (err, user) {
			// 	api.log("deserialized User: "+JSON.stringify(user));
			// 	if (err) {
			// 		api.log("ERROR: "+err);
			// 	}
			// 	done(null, user);
			// });
		});

		app.connect.use(passport.initialize());
		app.connect.use(passport.session());

		app.connect.use('/api/auth/facebook',
			passport.authenticate('facebook', { scope: ['email'] })
		);

		app.connect.use('/api/auth/facebook/callback',
			passport.authenticate('facebook')
		);

		app.connect.use('/api/auth/github',
			passport.authenticate('github', { scope: ['user:email'] })
		);

		app.connect.use('/api/auth/github/callback',
			passport.authenticate('github')
		);

		api.passport = passport;

		next();
	}
};
<|endoftext|>


<commit_before>var util = require('util'),
    EventEmitter = require('events').EventEmitter;

var P = require('p-promise'),
    _ = require('lodash');

var Connection = require('./connection'),
    errors = require('./errors');

var MONITOR_INTERVAL = 30000;

var Pool = module.exports = function Pool(options)
{
    options = Object(options);
    this.clients = [];
    this.dead = [];

    var hosts = options.hosts = 'hosts' in options || !('host' in options) ? options.hosts : [options.host];
    if (!Array.isArray(hosts))
        throw Error('ScamandriosError: Invalid hosts supplied for connection pool');

    _.extend(this, options, function (destinationValue, sourceValue)
    {
        return sourceValue == null ? destinationValue : sourceValue;
    });
};
util.inherits(Pool, EventEmitter);

Pool.prototype.TTL = Connection.TTL;

Pool.prototype.hostPoolSize     = 1;
Pool.prototype.closing          = false;
Pool.prototype.consistencylevel = 1;

Pool.prototype.hosts            = null;
Pool.prototype.clients          = null;
Pool.prototype.dead             = null;
Pool.prototype.timeout          = null;
Pool.prototype.monitorInterval     = null;

Pool.prototype.keyspace         = null;
Pool.prototype.cqlVersion       = null;
Pool.prototype.user             = null;
Pool.prototype.password         = null;

Pool.prototype.getHost = function(clients)
{
    return clients[Math.floor(Math.random() * clients.length)];
};

Pool.prototype.createConnection = function(host)
{
    var options = _.pick(this, 'keyspace', 'user', 'password', 'timeout', 'cqlVersion', 'consistencylevel');
    options.host = host;
    options.TTL = this.TTL + Math.floor(Math.random() * 10000);
    var connection = new Connection(options);
    connection.on('error', _.bind(this.emit, this, 'error'));
    return connection;
};

Pool.prototype.connect = function()
{
    var deferred = P.defer(),
        self = this;
    var hosts = this.hosts,
        poolSize = this.hostPoolSize,
        pendingCount = hosts.length * poolSize;

    function handleSettle(isResolved, value)
    {
        pendingCount--;
        if (isResolved)
            deferred.resolve(value);
        if (!pendingCount)
        {
            deferred.reject(errors.create({ 'name': 'NoAvailableNodesException', 'why': 'Could Not Connect To Any Nodes' }));
        }
    }

    _.forEach(hosts, function (host)
    {
        _.times(poolSize, function ()
        {
            var connection = self.createConnection(host);
            connection.connect().then(function (keyspace)
            {
                handleSettle(true, keyspace);
                if (keyspace)
                    keyspace.connection = self;
                self.emit('log', 'connection established to cassandra@' + host);
                self.clients.push(connection);
                if (self.closing)
                    connection.close();
            }, function (error)
            {
                handleSettle(false);
                self.dead.push(host);
            });
        });
    });

    this.monitorInterval = setInterval(this.monitorConnections.bind(this), MONITOR_INTERVAL);
    return deferred.promise;
};

Pool.prototype.use = function(keyspace)
{
    var self = this;
    return P.allSettled(_.map(this.clients, function (client)
    {
        return client.use(keyspace).then(function (keyspace)
        {
            if (keyspace)
                keyspace.connection = self;
            return keyspace;
        });
    }));
};

Pool.prototype.assignKeyspace = function(keyspace)
{
    var self = this;

    return this.use(keyspace)
    .then(function(promises)
    {
        var rejection = _.find(promises, function(promise) { return promise.state == 'rejected' && promise.reason.name == 'ScamandriosNotFoundException'; });
        if (!rejection)
            return promises;

        return self.createKeyspace(keyspace)
        .then(function() { return self.use(keyspace); })
        .then(function(responses)
        {
            var fulfillment = _.find(responses, { 'state': 'fulfilled' });
            if (!fulfillment)
            {
                var selectError = new Error('Failed to create and select keyspace.');
                _.assign(selectError, { 'keyspace': keyspace, 'responses': responses });
                throw selectError;
            }

            return responses;
        });
    });
};

Pool.prototype.getConnection = function(getHost)
{
    var host = (_.isFunction(getHost) ? getHost : this.getHost).call(this, this.clients);
    if (!host)
    {
        this.emit('error', errors.create({ 'name': 'NoAvailableNodesException', 'why': 'No Available Connections' }));
        return;
    }
    if (host.ready)
        return host;
    var clients = this.clients;
    for (var length = clients.length; length--;)
    {
        var client = clients[length];
        if (!client.ready)
        {
            clients.splice(length, 1);
            var deadhost = client.host + ':' + client.port;
            this.emit('log', 'getConnection() pushing host onto dead pool: ' + deadhost);
            this.dead.push(deadhost);
        }
    }
    return this.getConnection(getHost);
};

// If a node is alive in any useful sense, it will respond to this query.
// Nodes that time out or give bogus responses to this should go onto the
// dead list.
Pool.PING_QUERY = new Buffer('SELECT * FROM system.schema_keyspaces;');

Pool.prototype.monitorConnections = function()
{
    var self = this;
    if (this.closing)
        return;

    function checkDead()
    {
        if (self.closing)
            return;
        var dead = self.dead;
        if (dead.length)
        {
            var host = dead.pop(),
                connection = self.createConnection(host);
            return connection.connect()
            .then(function()
            {
                self.emit('log', 'cassandra host rising from the dead: ' + host);
                self.clients.push(connection);
            })
            .fail(function(err)
            {
                // self.emit('log', 'cassandra host still dead: ' + host + ':' + JSON.stringify(err));
                dead.push(host);
            }).done();
        }
    }

    function ping(client)
    {
        var timeout;

        function addToDeadPool()
        {
            var deadhost = client.host + ':' + client.port;
            self.emit('log', 'ping timeout to cassandra@' + deadhost);
            self.dead.push(deadhost);
            client.close();
            client.ready = false;
        }

        client.executeCQL(Pool.PING_QUERY)
        .then(function(result)
        {
            clearTimeout(timeout);
            // self.emit('log', 'good ping to cassandra@' + client.host + ':' + client.port);
        })
        .fail(function(error)
        {
            self.emit('log', 'connection error to cassandra@' + client.host + ':' + client.port + ' ' + JSON.stringify(error));
            clearTimeout(timeout);
            addToDeadPool();
        }).done();

        timeout = setTimeout(addToDeadPool, 7500);
    }

    _.each(self.clients, ping);
    if (self.dead.length)
        checkDead();
};

Pool.prototype.close = function()
{
    var clients = this.clients,
        pendingClients = clients.length,
        self = this;

    this.closing = true;
    clearInterval(this.monitorInterval);

    if (!pendingClients)
    {
        this.emit('close');
        return;
    }

    function onClose()
    {
        pendingClients--;
        if (!pendingClients)
            self.emit('close');
    }

    _.forEach(clients, function (client)
    {
        client.on('close', onClose).close();
    });
};

Pool.prototype.executeCQLAllClients = function(cqlBuffer, options)
{
    return P.all(_.map(this.clients, function (client)
    {
        return client.executeCQL(cqlBuffer, options);
    }));
};

_.each(['execute', 'executeCQL', 'cql', 'createKeyspace', 'dropKeyspace'], function (name)
{
    Pool.prototype[name] = function proxyToConnection()
    {
        var connection = this.getConnection();
        if (connection)
            return connection[name].apply(connection, arguments);
        var deferred = P.defer();
        deferred.reject(errors.create({ 'name': 'NoAvailableNodesException', 'why': 'Could Not Connect To Any Nodes' }));
        return deferred.promise;
    };
});
<commit_msg>If we've already called connect() on a pool, short-circuit out.<commit_after>var util = require('util'),
    EventEmitter = require('events').EventEmitter;

var P = require('p-promise'),
    _ = require('lodash');

var Connection = require('./connection'),
    errors = require('./errors');

var MONITOR_INTERVAL = 30000;

var Pool = module.exports = function Pool(options)
{
    options = Object(options);
    this.clients = [];
    this.dead = [];

    var hosts = options.hosts = 'hosts' in options || !('host' in options) ? options.hosts : [options.host];
    if (!Array.isArray(hosts))
        throw Error('ScamandriosError: Invalid hosts supplied for connection pool');

    _.extend(this, options, function (destinationValue, sourceValue)
    {
        return sourceValue == null ? destinationValue : sourceValue;
    });
};
util.inherits(Pool, EventEmitter);

Pool.prototype.TTL = Connection.TTL;

Pool.prototype.hostPoolSize     = 1;
Pool.prototype.closing          = false;
Pool.prototype.consistencylevel = 1;

Pool.prototype.hosts            = null;
Pool.prototype.clients          = null;
Pool.prototype.dead             = null;
Pool.prototype.timeout          = null;
Pool.prototype.monitorInterval     = null;

Pool.prototype.keyspace         = null;
Pool.prototype.cqlVersion       = null;
Pool.prototype.user             = null;
Pool.prototype.password         = null;

Pool.prototype.getHost = function(clients)
{
    return clients[Math.floor(Math.random() * clients.length)];
};

Pool.prototype.createConnection = function(host)
{
    var options = _.pick(this, 'keyspace', 'user', 'password', 'timeout', 'cqlVersion', 'consistencylevel');
    options.host = host;
    options.TTL = this.TTL + Math.floor(Math.random() * 10000);
    var connection = new Connection(options);
    connection.on('error', _.bind(this.emit, this, 'error'));
    return connection;
};

Pool.prototype.connect = function()
{
    if (this.monitorInterval)
        return P(); // already connected

    var deferred = P.defer(),
        self = this;
    var hosts = this.hosts,
        poolSize = this.hostPoolSize,
        pendingCount = hosts.length * poolSize;

    function handleSettle(isResolved, value)
    {
        pendingCount--;
        if (isResolved)
            deferred.resolve(value);
        if (!pendingCount)
        {
            deferred.reject(errors.create({ 'name': 'NoAvailableNodesException', 'why': 'Could Not Connect To Any Nodes' }));
        }
    }

    _.forEach(hosts, function (host)
    {
        _.times(poolSize, function ()
        {
            var connection = self.createConnection(host);
            connection.connect().then(function (keyspace)
            {
                handleSettle(true, keyspace);
                if (keyspace)
                    keyspace.connection = self;
                self.emit('log', 'connection established to cassandra@' + host);
                self.clients.push(connection);
                if (self.closing)
                    connection.close();
            }, function (error)
            {
                handleSettle(false);
                self.dead.push(host);
            });
        });
    });

    this.monitorInterval = setInterval(this.monitorConnections.bind(this), MONITOR_INTERVAL);
    return deferred.promise;
};

Pool.prototype.use = function(keyspace)
{
    var self = this;
    return P.allSettled(_.map(this.clients, function (client)
    {
        return client.use(keyspace).then(function (keyspace)
        {
            if (keyspace)
                keyspace.connection = self;
            return keyspace;
        });
    }));
};

Pool.prototype.assignKeyspace = function(keyspace)
{
    var self = this;

    return this.use(keyspace)
    .then(function(promises)
    {
        var rejection = _.find(promises, function(promise) { return promise.state == 'rejected' && promise.reason.name == 'ScamandriosNotFoundException'; });
        if (!rejection)
            return promises;

        return self.createKeyspace(keyspace)
        .then(function() { return self.use(keyspace); })
        .then(function(responses)
        {
            var fulfillment = _.find(responses, { 'state': 'fulfilled' });
            if (!fulfillment)
            {
                var selectError = new Error('Failed to create and select keyspace.');
                _.assign(selectError, { 'keyspace': keyspace, 'responses': responses });
                throw selectError;
            }

            return responses;
        });
    });
};

Pool.prototype.getConnection = function(getHost)
{
    var host = (_.isFunction(getHost) ? getHost : this.getHost).call(this, this.clients);
    if (!host)
    {
        this.emit('error', errors.create({ 'name': 'NoAvailableNodesException', 'why': 'No Available Connections' }));
        return;
    }
    if (host.ready)
        return host;
    var clients = this.clients;
    for (var length = clients.length; length--;)
    {
        var client = clients[length];
        if (!client.ready)
        {
            clients.splice(length, 1);
            var deadhost = client.host + ':' + client.port;
            this.emit('log', 'getConnection() pushing host onto dead pool: ' + deadhost);
            this.dead.push(deadhost);
        }
    }
    return this.getConnection(getHost);
};

// If a node is alive in any useful sense, it will respond to this query.
// Nodes that time out or give bogus responses to this should go onto the
// dead list.
Pool.PING_QUERY = new Buffer('SELECT * FROM system.schema_keyspaces;');

Pool.prototype.monitorConnections = function()
{
    var self = this;
    if (this.closing)
        return;

    function checkDead()
    {
        if (self.closing)
            return;
        var dead = self.dead;
        if (dead.length)
        {
            var host = dead.pop(),
                connection = self.createConnection(host);
            return connection.connect()
            .then(function()
            {
                self.emit('log', 'cassandra host rising from the dead: ' + host);
                self.clients.push(connection);
            })
            .fail(function(err)
            {
                // self.emit('log', 'cassandra host still dead: ' + host + ':' + JSON.stringify(err));
                dead.push(host);
            }).done();
        }
    }

    function ping(client)
    {
        var timeout;

        function addToDeadPool()
        {
            var deadhost = client.host + ':' + client.port;
            self.emit('log', 'ping timeout to cassandra@' + deadhost);
            self.dead.push(deadhost);
            client.close();
            client.ready = false;
        }

        client.executeCQL(Pool.PING_QUERY)
        .then(function(result)
        {
            clearTimeout(timeout);
            // self.emit('log', 'good ping to cassandra@' + client.host + ':' + client.port);
        })
        .fail(function(error)
        {
            self.emit('log', 'connection error to cassandra@' + client.host + ':' + client.port + ' ' + JSON.stringify(error));
            clearTimeout(timeout);
            addToDeadPool();
        }).done();

        timeout = setTimeout(addToDeadPool, 7500);
    }

    _.each(self.clients, ping);
    if (self.dead.length)
        checkDead();
};

Pool.prototype.close = function()
{
    var clients = this.clients,
        pendingClients = clients.length,
        self = this;

    this.closing = true;
    clearInterval(this.monitorInterval);

    if (!pendingClients)
    {
        this.emit('close');
        return;
    }

    function onClose()
    {
        pendingClients--;
        if (!pendingClients)
            self.emit('close');
    }

    _.forEach(clients, function (client)
    {
        client.on('close', onClose).close();
    });
};

Pool.prototype.executeCQLAllClients = function(cqlBuffer, options)
{
    return P.all(_.map(this.clients, function (client)
    {
        return client.executeCQL(cqlBuffer, options);
    }));
};

_.each(['execute', 'executeCQL', 'cql', 'createKeyspace', 'dropKeyspace'], function (name)
{
    Pool.prototype[name] = function proxyToConnection()
    {
        var connection = this.getConnection();
        if (connection)
            return connection[name].apply(connection, arguments);
        var deferred = P.defer();
        deferred.reject(errors.create({ 'name': 'NoAvailableNodesException', 'why': 'Could Not Connect To Any Nodes' }));
        return deferred.promise;
    };
});
<|endoftext|>