<commit_before>'use strict';

var metaphone,
    assert;

/**
 * Module dependencies.
 */

metaphone = require('./');
assert = require('assert');

/**
 * Unit tests.
 */

describe('metaphone(value)', function () {
    it('should be of type `function`', function () {
        assert(typeof metaphone === 'function');
    });

    it('should drop duplicate adjacent letters', function () {
        assert(metaphone('Agrippa') === 'AKRP');
    });

    it('should not drop duplicate adjacent C\'s', function () {
        assert(metaphone('hiccups') === 'HKKPS');
    });

    it('should drop the initial K when followed by N', function () {
        assert(metaphone('knack') === 'NK');
    });

    it('should drop the initial G when followed by N', function () {
        assert(metaphone('gnarl') === 'NRL');
    });

    it('should drop the initial P when followed by N', function () {
        assert(metaphone('pneumatics') === 'NMTKS');
    });

    it('should drop the initial A when followed by E', function () {
        assert(metaphone('aerial') === 'ERL');
    });

    it('should drop the initial W when followed by R', function () {
        assert(metaphone('wrestler') === 'RSTLR');
    });

    it('should drop the final B when preceded by M', function () {
        assert(metaphone('climb') === 'KLM');
    });

    it('should transform C to X if followed by IA', function () {
        // ...which in turn will be transformed to `ks` later.
        assert(metaphone('arithmetician') === 'AR0MTKSN');
    });

    it('should transform C to X, if not preceded by S and followed by H',
        function () {
            // ...which in turn will be transformed to `ks` later.
            assert(metaphone('abroach') === 'ABRKSH');
        }
    );

    it('should NOT transform C to X, if preceded by S and followed by H',
        function () {
            assert(metaphone('discharge') === 'TSKHRJ');
        }
    );

    it('should transform C to S if followed by I', function () {
        // ...which in turn will be transformed to `x` later.
        // ...which in turn will be transformed to `ks` later.
        assert(metaphone('vicious') === 'FKSS');
    });

    it('should transform C to S if followed by E', function () {
        assert(metaphone('vice') === 'FS');
    });

    it('should transform C to S if followed by Y', function () {
        assert(metaphone('conspiracy') === 'KNSPRS');
    });

    it('should transform remaining C\'s to K', function () {
        assert(metaphone('abject') === 'ABJKT');
    });

    it('should transform D to J if followed by GE', function () {
        assert(metaphone('abridge') === 'ABRJJ');
    });

    it('should transform D to J if followed by GY', function () {
        assert(metaphone('sedgy') === 'SJJ');
    });

    it('should transform D to J if followed by GI', function () {
        assert(metaphone('grudging') === 'KRJJNK');
    });

    it('should transform remaining D\'s to T', function () {
        assert(metaphone('abandon') === 'ABNTN');
    });

    it('should drop G if followed by H, and not $ (end-of-string) or ' +
        'vowel', function () {
            assert(metaphone('affright') === 'AFRT');
        }
    );

    it('should drop G if followed by N or NED, and $ (end-of-string)',
        function () {
            assert(metaphone('arraign') === 'ARN');

            assert(metaphone('assigned') === 'ASKNT');
        }
    );

    it('should transform G to J if not preceded by G, and followed by I',
        function () {
            assert(metaphone('agile') === 'AJL');
        }
    );

    it('should transform G to J if not preceded by G, and followed by E',
        function () {
            assert(metaphone('allege') === 'ALJ');
        }
    );

    it('should transform G to J if not preceded by G, and followed by Y',
        function () {
            assert(metaphone('apology') === 'APLJ');
        }
    );

    it('should transform remaining G\'s to K', function () {
        assert(metaphone('young') === 'YNK');
    });

    it('should drop H when preceded by a vowel and not followed by a vowel',
        function () {
            assert(metaphone('pharaoh') === 'FR');
        }
    );

    it('should transform CK to K', function () {
        assert(metaphone('antick') === 'ANTK');
    });

    it('should transform PH to F', function () {
        assert(metaphone('alphabet') === 'ALFBT');
    });

    it('should transform Q to K', function () {
        assert(metaphone('aqua') === 'AK');
    });

    it('should transform S to X when followed by H', function () {
        // ...which in turn will be transformed to `ks` later.
        assert(metaphone('abash') === 'ABKSH');
    });

    it('should transform S to X when followed by IA', function () {
        // ...which in turn will be transformed to `ks` later.
        assert(metaphone('Asia') === 'AKS');
    });

    it('should transform S to X when followed by IO', function () {
        assert(metaphone('decision') === 'TSKSN');
    });

    it('should transform T to X when followed by IA', function () {
        assert(metaphone('dalmatian') === 'TLMXN');
    });

    it('should transform T to X when followed by IO', function () {
        assert(metaphone('alteration') === 'ALTRXN');
    });

    it('should transform TH to 0 (a zero)', function () {
        assert(metaphone('although') === 'AL0KH');
    });

    it('should drop T if followed by CH', function () {
        assert(metaphone('dispatch') === 'TSPTKSH');
    });

    it('should transform V to F', function () {
        assert(metaphone('above') === 'ABF');
    });

    it('should transform WH to W if preceded by ^ (start-of-string)',
        function () {
            assert(metaphone('whale') === 'WL');
        }
    );

    it('should drop W if not followed by a vowel', function () {
        assert(metaphone('allow') === 'AL');
    });

    it('should transform X to S if preceded by ^ (start-of-string)',
        function () {
            assert(metaphone('Xanthippe') === 'SN0P');
        }
    );

    it('should transform remaining X\'s to KS', function () {
        assert(metaphone('axe') === 'AKS');
    });

    it('should drop Y if not followed by a vowel', function () {
        assert(metaphone('betrays') === 'BTRS');
    });

    it('should transform Z to S', function () {
        assert(metaphone('amazed') === 'AMST');
    });

    it('should drop all vowels unless preceded by ^ (start-of-string)',
        function () {
            assert(metaphone('appearance') === 'APRNS');
        }
    );

    it('should not ignore casing', function () {
        var result = metaphone('hiccups');
        assert(metaphone('HICCUPS') === result);
        assert(metaphone('HiCcUpS') === result);
    });
});

/**
 * Tests that this module returns the same results
 * as Natural.
 *
 * Source:
 *   https://github.com/NaturalNode/natural
 */

describe('Compatibility with Natural', function () {
    var fixtures = {
        'ablaze': 'ABLS',
        'transition': 'TRNSXN',
        'astronomical': 'ASTRNMKL',
        'buzzard': 'BSRT',
        'wonderer': 'WNTRR',
        'district': 'TSTRKT',
        'hockey': 'HK',
        'capital': 'KPTL',
        'penguin': 'PNKN',
        'garbonzo': 'KRBNS',
        'lightning': 'LTNNK',
        'light': 'LT'
    };

    Object.keys(fixtures).forEach(function (fixture) {
        var result;

        result = fixtures[fixture];

        it('should process `' + fixture + '` to `' + result + '`',
            function () {
                assert(metaphone(fixture) === result);
            }
        );
    });
});
<commit_msg>Fix incorrect executive rights on `test.js`<commit_after>'use strict';

var metaphone,
    assert;

/**
 * Module dependencies.
 */

metaphone = require('./');
assert = require('assert');

/**
 * Unit tests.
 */

describe('metaphone(value)', function () {
    it('should be of type `function`', function () {
        assert(typeof metaphone === 'function');
    });

    it('should drop duplicate adjacent letters', function () {
        assert(metaphone('Agrippa') === 'AKRP');
    });

    it('should not drop duplicate adjacent C\'s', function () {
        assert(metaphone('hiccups') === 'HKKPS');
    });

    it('should drop the initial K when followed by N', function () {
        assert(metaphone('knack') === 'NK');
    });

    it('should drop the initial G when followed by N', function () {
        assert(metaphone('gnarl') === 'NRL');
    });

    it('should drop the initial P when followed by N', function () {
        assert(metaphone('pneumatics') === 'NMTKS');
    });

    it('should drop the initial A when followed by E', function () {
        assert(metaphone('aerial') === 'ERL');
    });

    it('should drop the initial W when followed by R', function () {
        assert(metaphone('wrestler') === 'RSTLR');
    });

    it('should drop the final B when preceded by M', function () {
        assert(metaphone('climb') === 'KLM');
    });

    it('should transform C to X if followed by IA', function () {
        // ...which in turn will be transformed to `ks` later.
        assert(metaphone('arithmetician') === 'AR0MTKSN');
    });

    it('should transform C to X, if not preceded by S and followed by H',
        function () {
            // ...which in turn will be transformed to `ks` later.
            assert(metaphone('abroach') === 'ABRKSH');
        }
    );

    it('should NOT transform C to X, if preceded by S and followed by H',
        function () {
            assert(metaphone('discharge') === 'TSKHRJ');
        }
    );

    it('should transform C to S if followed by I', function () {
        // ...which in turn will be transformed to `x` later.
        // ...which in turn will be transformed to `ks` later.
        assert(metaphone('vicious') === 'FKSS');
    });

    it('should transform C to S if followed by E', function () {
        assert(metaphone('vice') === 'FS');
    });

    it('should transform C to S if followed by Y', function () {
        assert(metaphone('conspiracy') === 'KNSPRS');
    });

    it('should transform remaining C\'s to K', function () {
        assert(metaphone('abject') === 'ABJKT');
    });

    it('should transform D to J if followed by GE', function () {
        assert(metaphone('abridge') === 'ABRJJ');
    });

    it('should transform D to J if followed by GY', function () {
        assert(metaphone('sedgy') === 'SJJ');
    });

    it('should transform D to J if followed by GI', function () {
        assert(metaphone('grudging') === 'KRJJNK');
    });

    it('should transform remaining D\'s to T', function () {
        assert(metaphone('abandon') === 'ABNTN');
    });

    it('should drop G if followed by H, and not $ (end-of-string) or ' +
        'vowel', function () {
            assert(metaphone('affright') === 'AFRT');
        }
    );

    it('should drop G if followed by N or NED, and $ (end-of-string)',
        function () {
            assert(metaphone('arraign') === 'ARN');

            assert(metaphone('assigned') === 'ASKNT');
        }
    );

    it('should transform G to J if not preceded by G, and followed by I',
        function () {
            assert(metaphone('agile') === 'AJL');
        }
    );

    it('should transform G to J if not preceded by G, and followed by E',
        function () {
            assert(metaphone('allege') === 'ALJ');
        }
    );

    it('should transform G to J if not preceded by G, and followed by Y',
        function () {
            assert(metaphone('apology') === 'APLJ');
        }
    );

    it('should transform remaining G\'s to K', function () {
        assert(metaphone('young') === 'YNK');
    });

    it('should drop H when preceded by a vowel and not followed by a vowel',
        function () {
            assert(metaphone('pharaoh') === 'FR');
        }
    );

    it('should transform CK to K', function () {
        assert(metaphone('antick') === 'ANTK');
    });

    it('should transform PH to F', function () {
        assert(metaphone('alphabet') === 'ALFBT');
    });

    it('should transform Q to K', function () {
        assert(metaphone('aqua') === 'AK');
    });

    it('should transform S to X when followed by H', function () {
        // ...which in turn will be transformed to `ks` later.
        assert(metaphone('abash') === 'ABKSH');
    });

    it('should transform S to X when followed by IA', function () {
        // ...which in turn will be transformed to `ks` later.
        assert(metaphone('Asia') === 'AKS');
    });

    it('should transform S to X when followed by IO', function () {
        assert(metaphone('decision') === 'TSKSN');
    });

    it('should transform T to X when followed by IA', function () {
        assert(metaphone('dalmatian') === 'TLMXN');
    });

    it('should transform T to X when followed by IO', function () {
        assert(metaphone('alteration') === 'ALTRXN');
    });

    it('should transform TH to 0 (a zero)', function () {
        assert(metaphone('although') === 'AL0KH');
    });

    it('should drop T if followed by CH', function () {
        assert(metaphone('dispatch') === 'TSPTKSH');
    });

    it('should transform V to F', function () {
        assert(metaphone('above') === 'ABF');
    });

    it('should transform WH to W if preceded by ^ (start-of-string)',
        function () {
            assert(metaphone('whale') === 'WL');
        }
    );

    it('should drop W if not followed by a vowel', function () {
        assert(metaphone('allow') === 'AL');
    });

    it('should transform X to S if preceded by ^ (start-of-string)',
        function () {
            assert(metaphone('Xanthippe') === 'SN0P');
        }
    );

    it('should transform remaining X\'s to KS', function () {
        assert(metaphone('axe') === 'AKS');
    });

    it('should drop Y if not followed by a vowel', function () {
        assert(metaphone('betrays') === 'BTRS');
    });

    it('should transform Z to S', function () {
        assert(metaphone('amazed') === 'AMST');
    });

    it('should drop all vowels unless preceded by ^ (start-of-string)',
        function () {
            assert(metaphone('appearance') === 'APRNS');
        }
    );

    it('should not ignore casing', function () {
        var result = metaphone('hiccups');
        assert(metaphone('HICCUPS') === result);
        assert(metaphone('HiCcUpS') === result);
    });
});

/**
 * Tests that this module returns the same results
 * as Natural.
 *
 * Source:
 *   https://github.com/NaturalNode/natural
 */

describe('Compatibility with Natural', function () {
    var fixtures = {
        'ablaze': 'ABLS',
        'transition': 'TRNSXN',
        'astronomical': 'ASTRNMKL',
        'buzzard': 'BSRT',
        'wonderer': 'WNTRR',
        'district': 'TSTRKT',
        'hockey': 'HK',
        'capital': 'KPTL',
        'penguin': 'PNKN',
        'garbonzo': 'KRBNS',
        'lightning': 'LTNNK',
        'light': 'LT'
    };

    Object.keys(fixtures).forEach(function (fixture) {
        var result;

        result = fixtures[fixture];

        it('should process `' + fixture + '` to `' + result + '`',
            function () {
                assert(metaphone(fixture) === result);
            }
        );
    });
});
<|endoftext|>


<commit_before>/**
 * The Relais card communication protocol implementation.
 * Taken from my old "Relais.cs".
 * @module io/relais
 * @author Sören Gade
 *
 * @requires serialport
 * */

/**
 * A callback that simly indicated whether a certain task was successful.
 * @callback SuccessCallback
 * @param {bool} success
 * */

var util = require('util');
var async = require('async');
var Serial = require('./serial').Serial;

/**
 * Options for the serial port.
 * @constant
 * @type {Object}
 * @default
 * */
var SERIAL_OPTIONS = {
  baudrate: 19200,
  databits: 8,
  stopbits: 1,
  parity: 'none'
};
/**
 * Commands the Relais card understands.
 * @constant
 * @type {Object}
 * @default
 * */
var Commands = {
  NoOperation: 0,
  Setup: 1,
  GetPort: 2,
  SetPort: 3,
  Getption: 4,
  SetOption: 5,
  SetSingle: 6,
  DelSingle: 7,
  Toggle: 8
};
/**
 * Relais can be identified via a certain byte. These are there values.
 * @constant
 * @type {Object}
 * @default
 * */
var RelaisByteCount = {
  One: 1,
  Two: 2,
  Three: 4,
  Four: 8,
  Five: 16,
  Six: 32,
  Seven: 64,
  Eight: 128
};
/**
 * Name for the part of the messages send between us and the relais card.
 * @constant
 * @type {Object}
 * @default
 * */
var RelaisByteNames = {
  Command: 0,
  Address: 1,
  DataByte: 2,
  CheckSum: 3
};

/**
 * @constructor
 * @extends events.EventEmitter
 * */
function Relais(port) {
  /**
   * The id our card has.
   * @instance
   * */
  this.relaisID = 0;

  // our custom parser
  // emit after 4 bytes each
  SERIAL_OPTIONS.parser = (function() {
    var blockSize = 4;
    var data = new Buffer(0);

    return function(emitter, buffer) {
      data = new Buffer( data + buffer );

      var numParts = data.length / blockSize;
      var numRest = data.length % blockSize;

      var parts = [];
      for ( var i = 0; i < numParts; i++ ) {
        var buf = new Buffer(blockSize);
        data.copy(buf, 0, i * blockSize, i * blockSize + blockSize);

        parts.push(buf);
      }
      if ( numRest <= 0 ) {
        data = new Buffer(0);
      } else {
        var tmp = new Buffer(numRest);
        data.copy(tmp, 0, data.length - 1 - numRest, data.length - 1 - numRest + blockSize);
        data = tmp;
      }

      parts.forEach(function(bufferPart) {
        emitter.emit('data', bufferPart);
      });
    };

  }());
  Serial.call(this, port, SERIAL_OPTIONS);

  /* ==========
   * PRIVATE
   * ==========
   * */
  /**
   * @param {uint} delay
   * @param {Function} relaisOperation - An operation that is passed a relais number that it should work on.
   * @param {Callback} callback
   * */
  var _iterateAllRelais = function(delay, relaisOperation, callback) {
    var self = this;
    delay = ( delay > 0 ) ? delay : 0;
    callback = callback || function() {};

    if ( delay === 0 ) {
      relaisOperation.call(self, self.getAllRelais());
    } else {
      var relaisNums = [ 1, 2, 4, 8, 16, 32, 64, 128 ];

      async.eachSeries(relaisNums, function(item, cb) {

        // item == relaisnum
        relaisOperation.call(self, item);

        setTimeout(function() {
          cb();
        }, delay);

      }, function(err) {
        if ( err ) {
          callback(err);
          throw err;
        }
        // done
        callback(null);
      });

    }
  };

  /* ==========
   * PUBLIC
   * ==========
   * */
  /*
   * Disclaimer:
   * Ported directly from old .cs source file:
   * | | | | | | | | | | | | | | | | | | | | |
   * | | | | | | | | | | | | | | | | | | | | |
   * v v v v v v v v v v v v v v v v v v v v v
   * */
  /**
   * @param {byte} command
   * @param {byte} [data]
   * @param {Callback} callback - Callback for Relais#write (Error) and Relais#read (Result).
   * */
  this.send = function(command, data, callback) {
    var self = this;
    if ( !callback ) {
      if ( typeof data !== "function" ) {
        callback = data;
        data = 0;
      }
    }

    if ( !self.isOpen ) {
      return callback(new Error('Relais port is closed.'));
    }

    var buffer = new Buffer(4);
    buffer[RelaisByteNames.Command] = command;
    buffer[RelaisByteNames.Address] = self.relaisID;
    buffer[RelaisByteNames.DataByte] = data;
    buffer[RelaisByteNames.CheckSum] = ( command ^ self.relaisID ^ data );

    // call callback after write
    self.serialPort.once('data', function(data) {

      console.log("Response from relais card:", data);
      if ( typeof data !== "object" ) { // should be "Buffer"
        throw new Error("Invalid response data from relais card:", data);
      }

      var responseCommand = data[RelaisByteNames.Command];
      var responseAddress = data[RelaisByteNames.Address];
      if ( responseCommand === 255 ) { // error
        var err = new Error("Error from Relais card " + responseAddress + ".");
        return callback(err);
      }

      if ( responseCommand !== ( 255 - command ) ) {
        var err = new Error("Invalid response command. Expected " + ( 255 - command ) + " got " + responseCommand);
        return callback(err);
      }

      callback(null, data);

    });

    return self.write(buffer, function(err) {
      if ( err ) {
        callback(err);
      }
    });
  };

  this.getMoreRelais = function(relais1, relais2, relais3, relais4, relais5, relais6, relais7, relais8) {
    var retVal = ( RelaisByteCount.One * relais1 );
    retVal += ( RelaisByteCount.Two * relais2 );
    retVal += ( RelaisByteCount.Three * relais3 );
    retVal += ( RelaisByteCount.Four * relais4 );
    retVal += ( RelaisByteCount.Five * relais5 );
    retVal += ( RelaisByteCount.Six * relais6 );
    retVal += ( RelaisByteCount.Seven * relais7 );
    retVal += ( RelaisByteCount.Eight * relais8 );

    return retVal;
  };
  this.getAllRelais = function() {
    return this.getMoreRelais(1, 1, 1, 1, 1, 1, 1, 1);
  };

  /**
   * @param {Callback} [callback]
   * */
  this.noOperation = function(callback) {
    var self = this;
    callback = callback || function() {};

    return self.send(Commands.NoOperation, function(err, data) {
      if ( !!err ) {
        callback(err);
      }

      var ok = ( data[RelaisByteNames.Command] === 255 );
      callback(err, ok);

    });
  };
  /**
   * @param {Callback} [callback]
   * */
  this.NOP = function(callback) {
    return this.noOperation(callback);
  };

  /**
   * @param {Callback} [callback]
   * */
  this.setup = function(callback) {
    var self = this;
    callback = callback || function() {};

    if ( self.relaisID !== 0 ) {
      return callback(new Error("Relais ID is already set to", self.relaisID));
    }

    return self.send(Commands.Setup, function(err, data) {
      if ( !!err ) {
        return callback(err);
      }

      // set relais id according to response from relais card
      self.relaisID = data[RelaisByteNames.Address];

      callback(err, true);

    });
  };

  /**
   * @param {Callback} [callback]
   * */
  this.getPort = function(callback) {
    var self = this;
    callback = callback || function() {};

    self.send(Commands.GetPort, 0, function(err, data) {
      if ( err ) {
        callback(err);
      } else {

        if ( data[RelaisByteNames.Command] === ( 255 - Commands.GetPort ) ) {
          var port = data[RelaisByteNames.DataByte];
          callback(err, port);
        } else {
          callback(err, 0);
        }

      }
    });
  };

  /**
   * @param {byte} relais
   * */
  this.setPort = function(relais) {
    this.send(Commands.SetPort, relais);
  };

  /**
   * @param {Callback} [callback]
   * */
  this.getOption = function(callback) {
    var self = this;
    callback = callback || function() {};

    self.send(Commands.GetOption, 0, function(err, data) {
      if ( err ) {
        callback(err);
      } else {

        if ( data[RelaisByteNames.Command] === ( 255 - Commands.GetOption) ) {
          var dataByte = data[RelaisByteNames.DataByte];
          callback(err, dataByte);
        } else {
          callback(err, 0);
        }

      }
    });
  };

  /**
   * @param {byte} option
   * */
  this.setOption = function(option) {
    this.send(Commands.SetOption, option);
  };

  /**
   * @param {byte} relais
   * @param {Callback} [callback]
   * */
  this.setSingle = function(relais, callback) {
    var self = this;
    callback = callback || function() {};

    self.send(Commands.SetSingle, relais, function(err, data) {
      if ( err ) {
        callback(err);
      } else {

        if ( data[RelaisByteNames.Command] === ( 255 - Commands.SetSingle ) ) {
          var single = data[RelaisByteNames.DataByte];
          callback(err, single);
        } else {
          callback(err, 0);
        }

      }
    });
  };

  /**
   * @param {byte} relais
   * @param {Callback} [callback]
   * */
  this.delSingle = function(relais, callback) {
    var self = this;
    callback = callback || function() {};

    self.send(Commands.DelSingle, relais, function(err, data) {
      if ( err ) {
        callback(err);
      } else {

        if ( data[RelaisByteNames.Command] === ( 255 - Commands.DelSingle ) ) {
          var single = data[RelaisByteNames.DataByte];
          callback(err, single);
        } else {
          callback(err, 0);
        }

      }
    });
  };

  /**
   * @param {byte} relais
   * @param {Callback} [callback]
   * */
  this.toggle = function(relais, callback) {
    var self = this;
    callback = callback || function() {};

    self.send(Commands.Toggle, relais, function(err, data) {
      if ( err ) {
        callback(err);
      } else {

        if ( data[RelaisByteNames.Command] === ( 255 - Commands.Toggle ) ) {
          var resp = data[RelaisByteNames.DataByte];
          callback(err, resp);
        } else {
          callback(err, 0);
        }

      }
    });
  };

  /**
   * @param {int} delay
   * @param {Callback} [callback]
   * */
  this.activateAll = function(delay, callback) {
    _iterateAllRelais.call(this, delay, this.setSingle, callback);
  };

  /**
   * @param {int} delay
   * @param {Callback} [callback]
   * */
  this.deactivateAll = function(delay, callback) {
    _iterateAllRelais.call(this, delay, this.delSingle, callback);
  };
}
util.inherits(Relais, Serial);

module.exports = Relais;
<commit_msg>Fixed optional parameter assignment.<commit_after>/**
 * The Relais card communication protocol implementation.
 * Taken from my old "Relais.cs".
 * @module io/relais
 * @author Sören Gade
 *
 * @requires serialport
 * */

/**
 * A callback that simly indicated whether a certain task was successful.
 * @callback SuccessCallback
 * @param {bool} success
 * */

var util = require('util');
var async = require('async');
var Serial = require('./serial').Serial;

/**
 * Options for the serial port.
 * @constant
 * @type {Object}
 * @default
 * */
var SERIAL_OPTIONS = {
  baudrate: 19200,
  databits: 8,
  stopbits: 1,
  parity: 'none'
};
/**
 * Commands the Relais card understands.
 * @constant
 * @type {Object}
 * @default
 * */
var Commands = {
  NoOperation: 0,
  Setup: 1,
  GetPort: 2,
  SetPort: 3,
  Getption: 4,
  SetOption: 5,
  SetSingle: 6,
  DelSingle: 7,
  Toggle: 8
};
/**
 * Relais can be identified via a certain byte. These are there values.
 * @constant
 * @type {Object}
 * @default
 * */
var RelaisByteCount = {
  One: 1,
  Two: 2,
  Three: 4,
  Four: 8,
  Five: 16,
  Six: 32,
  Seven: 64,
  Eight: 128
};
/**
 * Name for the part of the messages send between us and the relais card.
 * @constant
 * @type {Object}
 * @default
 * */
var RelaisByteNames = {
  Command: 0,
  Address: 1,
  DataByte: 2,
  CheckSum: 3
};

/**
 * @constructor
 * @extends events.EventEmitter
 * */
function Relais(port) {
  /**
   * The id our card has.
   * @instance
   * */
  this.relaisID = 0;

  // our custom parser
  // emit after 4 bytes each
  SERIAL_OPTIONS.parser = (function() {
    var blockSize = 4;
    var data = new Buffer(0);

    return function(emitter, buffer) {
      data = new Buffer( data + buffer );

      var numParts = data.length / blockSize;
      var numRest = data.length % blockSize;

      var parts = [];
      for ( var i = 0; i < numParts; i++ ) {
        var buf = new Buffer(blockSize);
        data.copy(buf, 0, i * blockSize, i * blockSize + blockSize);

        parts.push(buf);
      }
      if ( numRest <= 0 ) {
        data = new Buffer(0);
      } else {
        var tmp = new Buffer(numRest);
        data.copy(tmp, 0, data.length - 1 - numRest, data.length - 1 - numRest + blockSize);
        data = tmp;
      }

      parts.forEach(function(bufferPart) {
        emitter.emit('data', bufferPart);
      });
    };

  }());
  Serial.call(this, port, SERIAL_OPTIONS);

  /* ==========
   * PRIVATE
   * ==========
   * */
  /**
   * @param {uint} delay
   * @param {Function} relaisOperation - An operation that is passed a relais number that it should work on.
   * @param {Callback} callback
   * */
  var _iterateAllRelais = function(delay, relaisOperation, callback) {
    var self = this;
    delay = ( delay > 0 ) ? delay : 0;
    callback = callback || function() {};

    if ( delay === 0 ) {
      relaisOperation.call(self, self.getAllRelais());
    } else {
      var relaisNums = [ 1, 2, 4, 8, 16, 32, 64, 128 ];

      async.eachSeries(relaisNums, function(item, cb) {

        // item == relaisnum
        relaisOperation.call(self, item);

        setTimeout(function() {
          cb();
        }, delay);

      }, function(err) {
        if ( err ) {
          callback(err);
          throw err;
        }
        // done
        callback(null);
      });

    }
  };

  /* ==========
   * PUBLIC
   * ==========
   * */
  /*
   * Disclaimer:
   * Ported directly from old .cs source file:
   * | | | | | | | | | | | | | | | | | | | | |
   * | | | | | | | | | | | | | | | | | | | | |
   * v v v v v v v v v v v v v v v v v v v v v
   * */
  /**
   * @param {byte} command
   * @param {byte} [data]
   * @param {Callback} callback - Callback for Relais#write (Error) and Relais#read (Result).
   * */
  this.send = function(command, data, callback) {
    var self = this;
    if ( !callback ) {
      if ( typeof data === "function" ) {
        callback = data;
        data = 0;
      } else {
        callback = function() {};
      }
    }

    if ( !self.isOpen ) {
      return callback(new Error('Relais port is closed.'));
    }

    var buffer = new Buffer(4);
    buffer[RelaisByteNames.Command] = command;
    buffer[RelaisByteNames.Address] = self.relaisID;
    buffer[RelaisByteNames.DataByte] = data;
    buffer[RelaisByteNames.CheckSum] = ( command ^ self.relaisID ^ data );

    // call callback after write
    self.serialPort.once('data', function(data) {

      console.log("Response from relais card:", data);
      if ( typeof data !== "object" ) { // should be "Buffer"
        throw new Error("Invalid response data from relais card:", data);
      }

      var responseCommand = data[RelaisByteNames.Command];
      var responseAddress = data[RelaisByteNames.Address];
      if ( responseCommand === 255 ) { // error
        var err = new Error("Error from Relais card " + responseAddress + ".");
        return callback(err);
      }

      if ( responseCommand !== ( 255 - command ) ) {
        var err = new Error("Invalid response command. Expected " + ( 255 - command ) + " got " + responseCommand);
        return callback(err);
      }

      callback(null, data);

    });

    return self.write(buffer, function(err) {
      if ( err ) {
        callback(err);
      }
    });
  };

  this.getMoreRelais = function(relais1, relais2, relais3, relais4, relais5, relais6, relais7, relais8) {
    var retVal = ( RelaisByteCount.One * relais1 );
    retVal += ( RelaisByteCount.Two * relais2 );
    retVal += ( RelaisByteCount.Three * relais3 );
    retVal += ( RelaisByteCount.Four * relais4 );
    retVal += ( RelaisByteCount.Five * relais5 );
    retVal += ( RelaisByteCount.Six * relais6 );
    retVal += ( RelaisByteCount.Seven * relais7 );
    retVal += ( RelaisByteCount.Eight * relais8 );

    return retVal;
  };
  this.getAllRelais = function() {
    return this.getMoreRelais(1, 1, 1, 1, 1, 1, 1, 1);
  };

  /**
   * @param {Callback} [callback]
   * */
  this.noOperation = function(callback) {
    var self = this;
    callback = callback || function() {};

    return self.send(Commands.NoOperation, function(err, data) {
      if ( !!err ) {
        callback(err);
      }

      var ok = ( data[RelaisByteNames.Command] === 255 );
      callback(err, ok);

    });
  };
  /**
   * @param {Callback} [callback]
   * */
  this.NOP = function(callback) {
    return this.noOperation(callback);
  };

  /**
   * @param {Callback} [callback]
   * */
  this.setup = function(callback) {
    var self = this;
    callback = callback || function() {};

    if ( self.relaisID !== 0 ) {
      return callback(new Error("Relais ID is already set to", self.relaisID));
    }

    return self.send(Commands.Setup, function(err, data) {
      if ( !!err ) {
        return callback(err);
      }

      // set relais id according to response from relais card
      self.relaisID = data[RelaisByteNames.Address];

      callback(err, true);

    });
  };

  /**
   * @param {Callback} [callback]
   * */
  this.getPort = function(callback) {
    var self = this;
    callback = callback || function() {};

    self.send(Commands.GetPort, 0, function(err, data) {
      if ( err ) {
        callback(err);
      } else {

        if ( data[RelaisByteNames.Command] === ( 255 - Commands.GetPort ) ) {
          var port = data[RelaisByteNames.DataByte];
          callback(err, port);
        } else {
          callback(err, 0);
        }

      }
    });
  };

  /**
   * @param {byte} relais
   * */
  this.setPort = function(relais) {
    this.send(Commands.SetPort, relais);
  };

  /**
   * @param {Callback} [callback]
   * */
  this.getOption = function(callback) {
    var self = this;
    callback = callback || function() {};

    self.send(Commands.GetOption, 0, function(err, data) {
      if ( err ) {
        callback(err);
      } else {

        if ( data[RelaisByteNames.Command] === ( 255 - Commands.GetOption) ) {
          var dataByte = data[RelaisByteNames.DataByte];
          callback(err, dataByte);
        } else {
          callback(err, 0);
        }

      }
    });
  };

  /**
   * @param {byte} option
   * */
  this.setOption = function(option) {
    this.send(Commands.SetOption, option);
  };

  /**
   * @param {byte} relais
   * @param {Callback} [callback]
   * */
  this.setSingle = function(relais, callback) {
    var self = this;
    callback = callback || function() {};

    self.send(Commands.SetSingle, relais, function(err, data) {
      if ( err ) {
        callback(err);
      } else {

        if ( data[RelaisByteNames.Command] === ( 255 - Commands.SetSingle ) ) {
          var single = data[RelaisByteNames.DataByte];
          callback(err, single);
        } else {
          callback(err, 0);
        }

      }
    });
  };

  /**
   * @param {byte} relais
   * @param {Callback} [callback]
   * */
  this.delSingle = function(relais, callback) {
    var self = this;
    callback = callback || function() {};

    self.send(Commands.DelSingle, relais, function(err, data) {
      if ( err ) {
        callback(err);
      } else {

        if ( data[RelaisByteNames.Command] === ( 255 - Commands.DelSingle ) ) {
          var single = data[RelaisByteNames.DataByte];
          callback(err, single);
        } else {
          callback(err, 0);
        }

      }
    });
  };

  /**
   * @param {byte} relais
   * @param {Callback} [callback]
   * */
  this.toggle = function(relais, callback) {
    var self = this;
    callback = callback || function() {};

    self.send(Commands.Toggle, relais, function(err, data) {
      if ( err ) {
        callback(err);
      } else {

        if ( data[RelaisByteNames.Command] === ( 255 - Commands.Toggle ) ) {
          var resp = data[RelaisByteNames.DataByte];
          callback(err, resp);
        } else {
          callback(err, 0);
        }

      }
    });
  };

  /**
   * @param {int} delay
   * @param {Callback} [callback]
   * */
  this.activateAll = function(delay, callback) {
    _iterateAllRelais.call(this, delay, this.setSingle, callback);
  };

  /**
   * @param {int} delay
   * @param {Callback} [callback]
   * */
  this.deactivateAll = function(delay, callback) {
    _iterateAllRelais.call(this, delay, this.delSingle, callback);
  };
}
util.inherits(Relais, Serial);

module.exports = Relais;
<|endoftext|>


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

  // The following colors will be used if you pick "Automatic" color.
  var BaseColors = {
    'Blue': '#4572A7',
    'Red': '#AA4643',
    'Green': '#89A54E',
    'Purple': '#80699B',
    'Cyan': '#3D96AE',
    'Orange': '#DB843D',
    'Light Blue': '#92A8CD',
    'Lilac': '#A47D7C',
    'Light Green': '#B5CA92',
    'Brown': '#A52A2A',
    'Black': '#000000',
    'Gray': '#808080',
    'Pink': '#FFC0CB',
    'Dark Blue': '#00008b'
  }

  // Additional colors for the user to choose from:
  var ColorPalette = _.extend({}, BaseColors, {
    'Indian Red': '#F8766D',
    'Green 2': '#53B400',
    'Green 3': '#00C094',
    'DarkTurquoise': '#00B6EB',
    'Dark Violet': '#A58AFF',
    'Pink 2' : '#FB61D7'
  });

  var ColorPaletteArray = _.values(BaseColors);

  var fillXValues = function(seriesList) {
    var xValues = _.sortBy(_.union.apply(_, _.pluck(seriesList, 'x')), _.identity);
    _.each(seriesList, function(series) {
      series.x = _.sortBy(series.x, _.identity);

      _.each(xValues, function(value, index) {
        if (series.x[index] !== value) {
          series.x.splice(index, 0, value);
          series.y.splice(index, 0, null);
        }
      });
    });
  };

  var normalAreaStacking = function(seriesList) {
    fillXValues(seriesList);
    _.each(seriesList, function(series) {
      series.text = [];
      series.hoverinfo = 'text+name';
    });
    for (var i = 0; i < seriesList.length; i++) {
      for (var j = 0; j < seriesList[i].y.length; j++) {
        var sum = i > 0 ? seriesList[i-1].y[j] : 0;
        seriesList[i].text.push('Value: ' + seriesList[i].y[j] + '
Sum: ' + (sum + seriesList[i].y[j]));
        seriesList[i].y[j] += sum;
      }
    }
  };

  var percentAreaStacking = function(seriesList) {
    if (seriesList.length === 0) {
      return;
    }

    fillXValues(seriesList);
    _.each(seriesList, function(series) {
      series.text = [];
      series.hoverinfo = 'text+name';
    });
    for (var i = 0; i < seriesList[0].y.length; i++) {
      var sum = 0;
      for(var j = 0; j < seriesList.length; j++) {
        sum += seriesList[j].y[i];
      }

      for(var j = 0; j < seriesList.length; j++) {
        var value = seriesList[j].y[i] / sum * 100;
        seriesList[j].text.push('Value: ' + seriesList[j].y[i] + '
Relative: ' + value.toFixed(2) + '%');

        seriesList[j].y[i] = value;
        if (j > 0) {
          seriesList[j].y[i] += seriesList[j-1].y[i];
        }
      }
    }
  };

  var percentBarStacking = function(seriesList) {
    if (seriesList.length === 0) {
      return;
    }

    fillXValues(seriesList);
    _.each(seriesList, function(series) {
      series.text = [];
      series.hoverinfo = 'text+name';
    });
    for (var i = 0; i < seriesList[0].y.length; i++) {
      var sum = 0;
      for(var j = 0; j < seriesList.length; j++) {
        sum += seriesList[j].y[i];
      }
      for(var j = 0; j < seriesList.length; j++) {
        var value = seriesList[j].y[i] / sum * 100;
        seriesList[j].text.push('Value: ' + seriesList[j].y[i] + '
Relative: ' + value.toFixed(2) + '%');
        seriesList[j].y[i] = value;
      }
    }
  }

  var normalizeValue = function(value) {
    if (moment.isMoment(value)) {
      return value.format("YYYY-MM-DD HH:mm:ss");
    }
    return value;
  }

  angular.module('plotly', [])
    .constant('ColorPalette', ColorPalette)
    .directive('plotlyChart', function () {
      return {
        restrict: 'E',
        template: '

',
        scope: {
          options: "=",
          series: "=",
          height: "="
        },
        link: function (scope, element) {
          var getScaleType = function(scale) {
            if (scale === 'datetime') {
              return 'date';
            }
            if (scale === 'logarithmic') {
              return 'log';
            }
            return scale;
          };

          var setType = function(series, type) {
            if (type === 'column') {
              series.type = 'bar';
            } else  if (type === 'line') {
              series.mode = 'lines';
            } else if (type === 'area') {
              series.fill = scope.options.series.stacking === null ? 'tozeroy' : 'tonexty';
              series.mode = 'lines';
            } else if (type === 'scatter') {
              series.type = 'scatter';
              series.mode = 'markers';
            }
          };

          var getColor = function(index) {
            return ColorPaletteArray[index % ColorPaletteArray.length];
          };

          var recalculateOptions = function() {
            scope.data.length = 0;
            scope.layout.showlegend = _.has(scope.options, 'legend') ? scope.options.legend.enabled : true;
            delete scope.layout.barmode;
            delete scope.layout.xaxis;
            delete scope.layout.yaxis;
            delete scope.layout.yaxis2;

            if (scope.options.globalSeriesType === 'pie') {
              var hasX = _.contains(_.values(scope.options.columnMapping), 'x');
              var rows = scope.series.length > 2 ? 2 : 1;
              var cellsInRow = Math.ceil(scope.series.length / rows);
              var cellWidth = 1 / cellsInRow;
              var cellHeight = 1 / rows;
              var xPadding = 0.02;
              var yPadding = 0.05;
              _.each(scope.series, function(series, index) {
                var xPosition = (index % cellsInRow) * cellWidth;
                var yPosition = Math.floor(index / cellsInRow) * cellHeight;
                var plotlySeries = {values: [], labels: [], type: 'pie', hole: .4,
                                    marker: {colors: ColorPaletteArray},
                                    text: series.name, textposition: 'inside', name: series.name,
                                    domain: {x: [xPosition, xPosition + cellWidth - xPadding],
                                             y: [yPosition, yPosition + cellHeight - yPadding]}};
                _.each(series.data, function(row, index) {
                  plotlySeries.values.push(row.y);
                  plotlySeries.labels.push(hasX ? row.x : 'Slice ' + index);
                });
                scope.data.push(plotlySeries);
              });
              return;
            }

            var hasY2 = false;
            var sortX = scope.options.sortX === true || scope.options.sortX === undefined;
            var useUnifiedXaxis = sortX && scope.options.xAxis.type === 'category';

            var unifiedX = null;
            if (useUnifiedXaxis) {
              unifiedX = _.sortBy(_.union.apply(_, _.map(scope.series, function(s) { return _.pluck(s.data, 'x'); })), _.identity);
            }

            _.each(scope.series, function(series, index) {
              var seriesOptions = scope.options.seriesOptions[series.name] || {};
              var plotlySeries = {x: [],
                                  y: [],
                                  name: seriesOptions.name || series.name,
                                  marker: {color: seriesOptions.color ? seriesOptions.color : getColor(index)}};

              if (seriesOptions.yAxis === 1 && (scope.options.series.stacking === null || seriesOptions.type === 'line')) {
                hasY2 = true;
                plotlySeries.yaxis = 'y2';
              }

              setType(plotlySeries, seriesOptions.type);
              var data = series.data;
              if (sortX) {
                data = _.sortBy(data, 'x');
              }

              if (useUnifiedXaxis && index === 0) {
                var values = {};
                _.each(data, function(row) {
                  values[row.x] = row.y;
                });

                _.each(unifiedX, function(x) {
                  plotlySeries.x.push(normalizeValue(x));
                  plotlySeries.y.push(normalizeValue(values[x] || null));
                });
              } else {
                _.each(data, function(row) {
                  plotlySeries.x.push(normalizeValue(row.x));
                  plotlySeries.y.push(normalizeValue(row.y));
                });
              }

              scope.data.push(plotlySeries);
            });

            var getTitle = function(axis) {
              if (angular.isDefined(axis) && angular.isDefined(axis.title)) {
                return axis.title.text;
              }
              return null;
            };

            scope.layout.xaxis = {title: getTitle(scope.options.xAxis),
                                  type: getScaleType(scope.options.xAxis.type)};
            if (angular.isDefined(scope.options.xAxis.labels)) {
              scope.layout.xaxis.showticklabels = scope.options.xAxis.labels.enabled;
            }
            if (angular.isArray(scope.options.yAxis)) {
              scope.layout.yaxis = {title: getTitle(scope.options.yAxis[0]),
                                    type: getScaleType(scope.options.yAxis[0].type)};
            }
            if (hasY2 && angular.isDefined(scope.options.yAxis)) {
              scope.layout.yaxis2 = {title: getTitle(scope.options.yAxis[1]),
                                     type: getScaleType(scope.options.yAxis[1].type),
                                     overlaying: 'y',
                                     side: 'right'};
            } else {
              delete scope.layout.yaxis2;
            }

            if (scope.options.series.stacking === 'normal') {
              scope.layout.barmode = 'stack';
              if (scope.options.globalSeriesType === 'area') {
                normalAreaStacking(scope.data);
              }
            } else if (scope.options.series.stacking === 'percent') {
              scope.layout.barmode = 'stack';
              if (scope.options.globalSeriesType === 'area') {
                percentAreaStacking(scope.data);
              } else if (scope.options.globalSeriesType === 'column') {
                percentBarStacking(scope.data);
              }
            }
          };

          scope.$watch('series', recalculateOptions);
          scope.$watch('options', recalculateOptions, true);

          scope.layout = {margin: {l: 50, r: 50, b: 50, t: 20, pad: 4}, height: scope.height, autosize: true, hovermode: 'closest'};
          scope.plotlyOptions = {showLink: false, displaylogo: false};
          scope.data = [];

          var element = element[0].children[0];
          Plotly.newPlot(element, scope.data, scope.layout, scope.plotlyOptions);

          scope.$watch('layout', function (layout, old) {
            if (angular.equals(layout, old)) {
              return;
            }
            Plotly.relayout(element, layout);
          }, true);

          scope.$watch('data', function (data, old) {
            Plotly.redraw(element);
          }, true);
        }
      };
    });
})();
<commit_msg>Fix #779: use the default chart type for new series<commit_after>(function () {
  'use strict';

  // The following colors will be used if you pick "Automatic" color.
  var BaseColors = {
    'Blue': '#4572A7',
    'Red': '#AA4643',
    'Green': '#89A54E',
    'Purple': '#80699B',
    'Cyan': '#3D96AE',
    'Orange': '#DB843D',
    'Light Blue': '#92A8CD',
    'Lilac': '#A47D7C',
    'Light Green': '#B5CA92',
    'Brown': '#A52A2A',
    'Black': '#000000',
    'Gray': '#808080',
    'Pink': '#FFC0CB',
    'Dark Blue': '#00008b'
  }

  // Additional colors for the user to choose from:
  var ColorPalette = _.extend({}, BaseColors, {
    'Indian Red': '#F8766D',
    'Green 2': '#53B400',
    'Green 3': '#00C094',
    'DarkTurquoise': '#00B6EB',
    'Dark Violet': '#A58AFF',
    'Pink 2' : '#FB61D7'
  });

  var ColorPaletteArray = _.values(BaseColors);

  var fillXValues = function(seriesList) {
    var xValues = _.sortBy(_.union.apply(_, _.pluck(seriesList, 'x')), _.identity);
    _.each(seriesList, function(series) {
      series.x = _.sortBy(series.x, _.identity);

      _.each(xValues, function(value, index) {
        if (series.x[index] !== value) {
          series.x.splice(index, 0, value);
          series.y.splice(index, 0, null);
        }
      });
    });
  };

  var normalAreaStacking = function(seriesList) {
    fillXValues(seriesList);
    _.each(seriesList, function(series) {
      series.text = [];
      series.hoverinfo = 'text+name';
    });
    for (var i = 0; i < seriesList.length; i++) {
      for (var j = 0; j < seriesList[i].y.length; j++) {
        var sum = i > 0 ? seriesList[i-1].y[j] : 0;
        seriesList[i].text.push('Value: ' + seriesList[i].y[j] + '
Sum: ' + (sum + seriesList[i].y[j]));
        seriesList[i].y[j] += sum;
      }
    }
  };

  var percentAreaStacking = function(seriesList) {
    if (seriesList.length === 0) {
      return;
    }

    fillXValues(seriesList);
    _.each(seriesList, function(series) {
      series.text = [];
      series.hoverinfo = 'text+name';
    });
    for (var i = 0; i < seriesList[0].y.length; i++) {
      var sum = 0;
      for(var j = 0; j < seriesList.length; j++) {
        sum += seriesList[j].y[i];
      }

      for(var j = 0; j < seriesList.length; j++) {
        var value = seriesList[j].y[i] / sum * 100;
        seriesList[j].text.push('Value: ' + seriesList[j].y[i] + '
Relative: ' + value.toFixed(2) + '%');

        seriesList[j].y[i] = value;
        if (j > 0) {
          seriesList[j].y[i] += seriesList[j-1].y[i];
        }
      }
    }
  };

  var percentBarStacking = function(seriesList) {
    if (seriesList.length === 0) {
      return;
    }

    fillXValues(seriesList);
    _.each(seriesList, function(series) {
      series.text = [];
      series.hoverinfo = 'text+name';
    });
    for (var i = 0; i < seriesList[0].y.length; i++) {
      var sum = 0;
      for(var j = 0; j < seriesList.length; j++) {
        sum += seriesList[j].y[i];
      }
      for(var j = 0; j < seriesList.length; j++) {
        var value = seriesList[j].y[i] / sum * 100;
        seriesList[j].text.push('Value: ' + seriesList[j].y[i] + '
Relative: ' + value.toFixed(2) + '%');
        seriesList[j].y[i] = value;
      }
    }
  }

  var normalizeValue = function(value) {
    if (moment.isMoment(value)) {
      return value.format("YYYY-MM-DD HH:mm:ss");
    }
    return value;
  }

  angular.module('plotly', [])
    .constant('ColorPalette', ColorPalette)
    .directive('plotlyChart', function () {
      return {
        restrict: 'E',
        template: '

',
        scope: {
          options: "=",
          series: "=",
          height: "="
        },
        link: function (scope, element) {
          var getScaleType = function(scale) {
            if (scale === 'datetime') {
              return 'date';
            }
            if (scale === 'logarithmic') {
              return 'log';
            }
            return scale;
          };

          var setType = function(series, type) {
            if (type === 'column') {
              series.type = 'bar';
            } else  if (type === 'line') {
              series.mode = 'lines';
            } else if (type === 'area') {
              series.fill = scope.options.series.stacking === null ? 'tozeroy' : 'tonexty';
              series.mode = 'lines';
            } else if (type === 'scatter') {
              series.type = 'scatter';
              series.mode = 'markers';
            }
          };

          var getColor = function(index) {
            return ColorPaletteArray[index % ColorPaletteArray.length];
          };

          var recalculateOptions = function() {
            scope.data.length = 0;
            scope.layout.showlegend = _.has(scope.options, 'legend') ? scope.options.legend.enabled : true;
            delete scope.layout.barmode;
            delete scope.layout.xaxis;
            delete scope.layout.yaxis;
            delete scope.layout.yaxis2;

            if (scope.options.globalSeriesType === 'pie') {
              var hasX = _.contains(_.values(scope.options.columnMapping), 'x');
              var rows = scope.series.length > 2 ? 2 : 1;
              var cellsInRow = Math.ceil(scope.series.length / rows);
              var cellWidth = 1 / cellsInRow;
              var cellHeight = 1 / rows;
              var xPadding = 0.02;
              var yPadding = 0.05;
              _.each(scope.series, function(series, index) {
                var xPosition = (index % cellsInRow) * cellWidth;
                var yPosition = Math.floor(index / cellsInRow) * cellHeight;
                var plotlySeries = {values: [], labels: [], type: 'pie', hole: .4,
                                    marker: {colors: ColorPaletteArray},
                                    text: series.name, textposition: 'inside', name: series.name,
                                    domain: {x: [xPosition, xPosition + cellWidth - xPadding],
                                             y: [yPosition, yPosition + cellHeight - yPadding]}};
                _.each(series.data, function(row, index) {
                  plotlySeries.values.push(row.y);
                  plotlySeries.labels.push(hasX ? row.x : 'Slice ' + index);
                });
                scope.data.push(plotlySeries);
              });
              return;
            }

            var hasY2 = false;
            var sortX = scope.options.sortX === true || scope.options.sortX === undefined;
            var useUnifiedXaxis = sortX && scope.options.xAxis.type === 'category';

            var unifiedX = null;
            if (useUnifiedXaxis) {
              unifiedX = _.sortBy(_.union.apply(_, _.map(scope.series, function(s) { return _.pluck(s.data, 'x'); })), _.identity);
            }

            _.each(scope.series, function(series, index) {
              var seriesOptions = scope.options.seriesOptions[series.name] || {type: scope.options.globalSeriesType};
              var plotlySeries = {x: [],
                                  y: [],
                                  name: seriesOptions.name || series.name,
                                  marker: {color: seriesOptions.color ? seriesOptions.color : getColor(index)}};

              if (seriesOptions.yAxis === 1 && (scope.options.series.stacking === null || seriesOptions.type === 'line')) {
                hasY2 = true;
                plotlySeries.yaxis = 'y2';
              }

              setType(plotlySeries, seriesOptions.type);
              var data = series.data;
              if (sortX) {
                data = _.sortBy(data, 'x');
              }

              if (useUnifiedXaxis && index === 0) {
                var values = {};
                _.each(data, function(row) {
                  values[row.x] = row.y;
                });

                _.each(unifiedX, function(x) {
                  plotlySeries.x.push(normalizeValue(x));
                  plotlySeries.y.push(normalizeValue(values[x] || null));
                });
              } else {
                _.each(data, function(row) {
                  plotlySeries.x.push(normalizeValue(row.x));
                  plotlySeries.y.push(normalizeValue(row.y));
                });
              }

              scope.data.push(plotlySeries);
            });

            var getTitle = function(axis) {
              if (angular.isDefined(axis) && angular.isDefined(axis.title)) {
                return axis.title.text;
              }
              return null;
            };

            scope.layout.xaxis = {title: getTitle(scope.options.xAxis),
                                  type: getScaleType(scope.options.xAxis.type)};
            if (angular.isDefined(scope.options.xAxis.labels)) {
              scope.layout.xaxis.showticklabels = scope.options.xAxis.labels.enabled;
            }
            if (angular.isArray(scope.options.yAxis)) {
              scope.layout.yaxis = {title: getTitle(scope.options.yAxis[0]),
                                    type: getScaleType(scope.options.yAxis[0].type)};
            }
            if (hasY2 && angular.isDefined(scope.options.yAxis)) {
              scope.layout.yaxis2 = {title: getTitle(scope.options.yAxis[1]),
                                     type: getScaleType(scope.options.yAxis[1].type),
                                     overlaying: 'y',
                                     side: 'right'};
            } else {
              delete scope.layout.yaxis2;
            }

            if (scope.options.series.stacking === 'normal') {
              scope.layout.barmode = 'stack';
              if (scope.options.globalSeriesType === 'area') {
                normalAreaStacking(scope.data);
              }
            } else if (scope.options.series.stacking === 'percent') {
              scope.layout.barmode = 'stack';
              if (scope.options.globalSeriesType === 'area') {
                percentAreaStacking(scope.data);
              } else if (scope.options.globalSeriesType === 'column') {
                percentBarStacking(scope.data);
              }
            }
          };

          scope.$watch('series', recalculateOptions);
          scope.$watch('options', recalculateOptions, true);

          scope.layout = {margin: {l: 50, r: 50, b: 50, t: 20, pad: 4}, height: scope.height, autosize: true, hovermode: 'closest'};
          scope.plotlyOptions = {showLink: false, displaylogo: false};
          scope.data = [];

          var element = element[0].children[0];
          Plotly.newPlot(element, scope.data, scope.layout, scope.plotlyOptions);

          scope.$watch('layout', function (layout, old) {
            if (angular.equals(layout, old)) {
              return;
            }
            Plotly.relayout(element, layout);
          }, true);

          scope.$watch('data', function (data, old) {
            Plotly.redraw(element);
          }, true);
        }
      };
    });
})();
<|endoftext|>


<commit_before>'use strict'

const assert = require('assert')
const graphql = require('graphql')
const lambdaGraphql = require('../index')

const schema = graphql.buildSchema(`
  type Query {
    hello(foo: String): String
  }
`)

const root = { hello: (params) => 'Hello world! ' + (params.foo || '') }

const handler = lambdaGraphql({
  schema: schema,
  rootValue: root
})

describe('handler', () => {
  it('should handle get request',(done) => {
    let event = {
      "path": "/",
      "httpMethod": "GET",
      queryStringParameters: {
        query: encodeURIComponent('query ($blah: String){hello(foo:$blah)}'),
        variables: '{"blah":"test"}'
      }
    }
    handler(event,{
      succeed: (result) => {
        assert.equal(result.statusCode,200)
        let body = JSON.parse(result.body)
        assert.equal('Hello world! test', body.data.hello)
        done()
      },
      failed: done
    })
  })
})
<commit_msg>Fix tests for updated api<commit_after>'use strict'

const assert = require('assert')
const graphql = require('graphql')
const lambdaGraphql = require('../index')

const schema = graphql.buildSchema(`
  type Query {
    hello(foo: String): String
  }
`)

const root = { hello: (params) => 'Hello world! ' + (params.foo || '') }

const app = lambdaGraphql({
  schema: schema,
  rootValue: root
})

describe('handler', () => {
  it('should handle get request',(done) => {
    let event = {
      "path": "/",
      "httpMethod": "GET",
      queryStringParameters: {
        query: encodeURIComponent('query ($blah: String){hello(foo:$blah)}'),
        variables: '{"blah":"test"}'
      }
    }
    app.handler(event,{
      succeed: (result) => {
        assert.equal(result.statusCode,200)
        let body = JSON.parse(result.body)
        assert.equal('Hello world! test', body.data.hello)
        done()
      },
      failed: done
    })
  })
})
<|endoftext|>


<commit_before>/*
  Copyright 2015 Xebia

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

const fs = require('fs');
const path = require('path');
const util = require('util');
const q = require('q');
const request = require('request');

const RUN_ID_FILE = '.visualreview-runid.pid';

module.exports = VisualReview;

function VisualReview(options) {
  var hostname = options.hostname || 'localhost';
  var port = options.port || 1337;

  this._callServer = function (method, path, formParams, multiPartFormOptions) {
    var defer = q.defer();

    var requestOptions = {
      method: method.toUpperCase(),
      uri: 'http://' + hostname + ':' + port + '/api/' + path
    };

    // for regular form parameters
    if (formParams) {
      requestOptions.form = formParams;
    }

    // for multipart forms
    if (multiPartFormOptions) {
      requestOptions.formData = multiPartFormOptions;
    }

    request(requestOptions, function (error, response, body) {
      if (error) {
        defer.reject(error);
      } else if (parseInt(response.statusCode) >= 400 || parseInt(response.statusCode < 600)) {
        defer.reject('Server returned status ' + response.statusCode + ": " + body);
      } else {
        try {
          defer.resolve(JSON.parse(body));
        } catch (e) {
          defer.reject("Could not parse JSON response from server " + e);
        }
      }
    });

    return defer.promise;
  };

  this._writeRunIdFile = function (runId) {
    var defer = q.defer();
    fs.writeFile(RUN_ID_FILE, runId, function(err) {
      if(err) {
        defer.reject("VisualReview-protractor: could not write temporary runid file. " + err)
      } else {
        defer.resolve(runId);
      }
    });

    return defer.promise;
  };

  this._readRunIdFile = function () {
    var defer = q.defer();

    fs.readFile(RUN_ID_FILE, function (err, data) {
      if (err) {
        defer.reject("VisualReview-protractor: could not read temporary runid file + " + err);
      } else {
        defer.resolve(data);
      }
    });

    return defer.promise;
  }

  this.initRun = function (projectName, suiteName) {
    return this._callServer('post', 'runs', {
      'project-name': projectName,
      'suite-name': suiteName
    }).then(
      function (result) {
        var createdRunId = result.id;
        if (createdRunId) {
          console.log("VisualReview-protractor: created run with ID", createdRunId);
          return this._writeRunIdFile(createdRunId);
        } else {
          throw new Error('VisualReview-protractor: VisualReview server returned an empty run id when creating a new run. Probably something went wrong with the server.');
        }
      }.bind(this),
      function (err) {
        throw new Error('VisualReview-protractor: an error occurred while creating a new run on the VisualReview server. ' + err);
      });
  };

  this._getMetaData = function (browser) {
    return browser.getCapabilities().then(function (caps) {
      return {
        'os': caps.caps_.platform,
        'browser': caps.caps_.browserName,
        'version': caps.caps_.version
      }
    }).then(function (metadata) {
      return browser.manage().window().getSize().then(function (size) {
        metadata.resolution = size.width + 'x' + size.height;
        return metadata;
      });
    });
  };

  this.takeScreenshot = function (name) {
    return browser.driver.controlFlow().execute(function () {

      return q.all([this._getMetaData(browser), browser.takeScreenshot(), this._readRunIdFile()]).then(function (results) {
        var metaData = results[0],
          png = results[1],
          runId = results[2];

        if (!runId) {
          throw Error('VisualReview-protractor: Could not send screenshot to VisualReview server, could not find any run ID. Was initRun called before starting this test? See VisualReview-protractor\'s documentation for more details on how to set this up.');
        }

        return this._callServer('post', 'runs/' + runId + '/screenshots', null, {
          'meta[os]': metaData.os,
          'meta[browser]': metaData.browser,
          'meta[version]': metaData.version,
          'meta[resolution]': metaData.resolution,
          'screenshot-name': name,
          file: {
            value: new Buffer(png, 'base64'),
            options: {
              filename: 'file.png',
              contentType: 'image/png'
            }
          }
        })
      }.bind(this)).then(
        function (response) {
          return response;
        },
        function (err) {
          throw Error('VisualReview-protractor: Something went wrong while sending a screenshot to the VisualReview server. ' + err);
        });
    }.bind(this));
  };

  this.cleanup = function () {
    var defer = q.defer();

    fs.unlink(RUN_ID_FILE, function (err) {
      if (err) {
        defer.reject(err);
      } else {
        defer.resolve();
      }
    });

    return defer.promise;
  }
}
<commit_msg>update server calls to use JSON body<commit_after>/*
 Copyright 2015 Xebia

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

const fs = require('fs');
const path = require('path');
const util = require('util');
const q = require('q');
const request = require('request');

const RUN_ID_FILE = '.visualreview-runid.pid';

module.exports = VisualReview;

function VisualReview(options) {
  var hostname = options.hostname || 'localhost';
  var port = options.port || 1337;

  this._callServer = function (method, path, jsonBody, multiPartFormOptions) {
    var defer = q.defer();

    var requestOptions = {
      method: method.toUpperCase(),
      uri: 'http://' + hostname + ':' + port + '/api/' + path
    };

    // for JSON body request
    if (jsonBody) {
      requestOptions.body = jsonBody;
      requestOptions.json = true;
    }

    // for multipart forms
    if (multiPartFormOptions) {
      requestOptions.formData = multiPartFormOptions;
    }

    request(requestOptions, function (error, response, body) {
      if (error) {
        defer.reject(error);
      } else if (parseInt(response.statusCode) >= 400 || parseInt(response.statusCode < 600)) {
        defer.reject('The VisualReview server returned status ' + response.statusCode + ": " + body);
      } else {
        try {
          defer.resolve(body);
        } catch (e) {
          defer.reject("Could not parse JSON response from server " + e);
        }
      }
    });

    return defer.promise;
  };

  this._writeRunIdFile = function (runId) {
    var defer = q.defer();
    fs.writeFile(RUN_ID_FILE, runId, function (err) {
      if (err) {
        defer.reject("VisualReview-protractor: could not write temporary runId file. " + err)
      } else {
        defer.resolve(runId);
      }
    });

    return defer.promise;
  };

  this._readRunIdFile = function () {
    var defer = q.defer();

    fs.readFile(RUN_ID_FILE, function (err, data) {
      if (err) {
        defer.reject("VisualReview-protractor: could not read temporary runId file + " + err);
      } else {
        defer.resolve(data);
      }
    });

    return defer.promise;
  };

  this.initRun = function (projectName, suiteName) {
    return this._callServer('post', 'runs', {
      'projectName': projectName,
      'suiteName': suiteName
    }).then(
      function (result) {
        var createdRunId = result.id;
        if (createdRunId) {
          console.log("VisualReview-protractor: created run with ID", createdRunId);
          return this._writeRunIdFile(createdRunId);
        } else {
          throw new Error('VisualReview-protractor: VisualReview server returned an empty run id when creating a new run. Probably something went wrong with the server.');
        }
      }.bind(this),
      function (err) {
        throw new Error('VisualReview-protractor: an error occurred while creating a new run on the VisualReview server. ' + err);
      });
  };

  this._getMetaData = function (browser) {
    return browser.getCapabilities().then(function (caps) {
      return {
        'os': caps.caps_.platform,
        'browser': caps.caps_.browserName,
        'version': caps.caps_.version
      }
    }).then(function (metadata) {
      return browser.manage().window().getSize().then(function (size) {
        metadata.resolution = size.width + 'x' + size.height;
        return metadata;
      });
    });
  };

  this.takeScreenshot = function (name) {
    return browser.driver.controlFlow().execute(function () {

      return q.all([this._getMetaData(browser), browser.takeScreenshot(), this._readRunIdFile()]).then(function (results) {
        var metaData = results[0],
          png = results[1],
          runId = results[2];

        if (!runId) {
          throw Error('VisualReview-protractor: Could not send screenshot to VisualReview server, could not find any run ID. Was initRun called before starting this test? See VisualReview-protractor\'s documentation for more details on how to set this up.');
        }

        return this._callServer('post', 'runs/' + runId + '/screenshots', null, {
          meta: JSON.stringify(metaData),
          screenshotName: name,
          file: {
            value: new Buffer(png, 'base64'),
            options: {
              filename: 'file.png',
              contentType: 'image/png'
            }
          }
        })
      }.bind(this)).then(
        function (response) {
          return response;
        },
        function (err) {
          throw Error('VisualReview-protractor: Something went wrong while sending a screenshot to the VisualReview server. ' + err);
        });
    }.bind(this));
  };

  this.cleanup = function () {
    var defer = q.defer();

    fs.unlink(RUN_ID_FILE, function (err) {
      if (err) {
        defer.reject(err);
      } else {
        defer.resolve();
      }
    });

    return defer.promise;
  }
}
<|endoftext|>


<commit_before>/**
 * Lite Scroll
 *
 * @version    0.3.4
 * @author     Aiden Foxx
 * @license    MIT License
 * @copyright  2015 Aiden Foxx
 * @link       http://github.com/aidenfoxx
 * @twitter    @furiousfoxx
 */
function LiteScroll(a,b){if(!(this instanceof LiteScroll))return new LiteScroll(a,b);this.container=a;this.content=a.children[0];this.scrollFrame=this.scrollBegin=this.scrollEvent=this.scrollLock=this.scrollCallback=null;this.scrollInitVec={x:0,y:0};this.scrollInitMouseVec={x:0,y:0};this.childRect=this.contentRect=this.containerRect=this.resizeTimeout=null;this.y=this.x=0;this.options={scrollX:!1,scrollY:!0,snap:!1,snapSpeed:300,dynamicResize:!0,scrollLock:!0,scrollLockThreshold:20,momentum:!0,momentumFalloff:.006,
gpuAcceleration:!1};for(var c in b)this.options[c]=b[c];this.resizeCallback();this.bindEvents()}LiteScroll.prototype.scrollStart=function(a){};LiteScroll.prototype.scroll=function(a){};LiteScroll.prototype.scrollEnd=function(a){};LiteScroll.prototype.calcRelativePos=function(a,b){return{x:a-this.containerRect.left,y:b-this.containerRect.top}};
LiteScroll.prototype.calcTouchCoords=function(a){return this.calcRelativePos(a.changedTouches?a.changedTouches[0].pageX:a.pageX,a.changedTouches?a.changedTouches[0].pageY:a.pageY)};LiteScroll.prototype.clacPointDistance=function(a,b){var c=b.x-a.x,d=b.y-a.y;return Math.sqrt(c*c+d*d)};
LiteScroll.prototype.calcNearestChild=function(){for(var a=null,b=0,c=0,d=this.childRect.length;c<d;c++){var e=this.calcRelativePos(this.childRect[c].left,this.childRect[c].top);e.x=-e.x;e.y=-e.y;e=this.clacPointDistance(this,e);if(!c||e<a)a=e,b=c}return b};
LiteScroll.prototype.getChildRect=function(){var a=[],b=this.content.style.transform;this.content.style.transitionDuration="0ms";this.content.style.transform=this.content.style.webkitTransform="translate(0px, 0px)";for(var c=0,d=this.content.children.length;c<d;c++)a.push(this.content.children[c].getBoundingClientRect());this.content.style.transform=this.content.style.webkitTransform=b;return a};
LiteScroll.prototype.bindEvents=function(){this.container.addEventListener("mousedown",this._scrollStart.bind(this));this.container.addEventListener("touchstart",this._scrollStart.bind(this));this.container.addEventListener("pointerdown",this._scrollStart.bind(this));this.container.addEventListener("MSPointerDown",this._scrollStart.bind(this));document.addEventListener("mouseup",this._scrollEnd.bind(this));document.addEventListener("touchend",this._scrollEnd.bind(this));document.addEventListener("touchcancel",
this._scrollEnd.bind(this));document.addEventListener("pointerout",this._scrollEnd.bind(this));document.addEventListener("MSPointerOut",this._scrollEnd.bind(this));this.options.dynamicResize&&window.addEventListener("resize",this.resize.bind(this))};LiteScroll.prototype.resize=function(){clearTimeout(this.resizeTimeout);this.resizeTimeout=setTimeout(function(){this.resizeCallback()}.bind(this),500)};
LiteScroll.prototype.resizeCallback=function(){this.containerRect=this.container.getBoundingClientRect();this.contentRect=this.content.getBoundingClientRect();this.childRect=this.getChildRect()};
LiteScroll.prototype.scrollTo=function(a,b,c,d,e){a=Math.round(a);b=Math.round(b);if(this.options.scrollX&&"y"!==this.scrollLock&&this.x!==a){var h=this.contentRect.width-this.containerRect.width;if(0<a||a<-h){var f=this.x-a;a=0<a?0:-h;f=Math.abs(this.x-a)/Math.abs(f)}this.x=a}if(this.options.scrollY&&"x"!==this.scrollLock&&this.y!==b){a=this.contentRect.height-this.containerRect.height;if(0<b||b<-a){var g=this.y-b;b=0<b?0:-a;g=Math.abs(this.y-b)/Math.abs(g)}this.y=b}!f&&g?c*=g:f&&!g?c*=f:f&&g&&(c*=
f<g?f:g);this.content.style.transform=this.content.style.webkitTransform="translate("+this.x+"px, "+this.y+"px)"+(this.gpuAcceleration?" translateZ(0px)":"");this.content.style.transitionDuration=c+"ms";this.content.style.transitionTimingFunction=d;clearTimeout(this.scrollCallback);e&&(this.scrollCallback=setTimeout(e.bind(this),c))};
LiteScroll.prototype.snapTo=function(a,b,c,d){if(!this.childRect[a])return!1;a=this.calcRelativePos(this.childRect[a].left,this.childRect[a].top);this.scrollTo(-a.x,-a.y,0<=b?b:this.options.snapSpeed,c?c:"cubic-bezier(0.1, 0.55, 0.1, 1)",d)};LiteScroll.prototype.snapToNearest=function(a,b,c){return this.snapTo(this.calcNearestChild(),a,b,c)};
LiteScroll.prototype._scrollStart=function(a){a.preventDefault();this.scrollEvent||(this.scrollBegin=Date.now(),this.scrollInitMouseVec=this.calcTouchCoords(a),this.scrollInitVec={x:this.x,y:this.y},this.scrollEvent=this._scroll.bind(this),this.container.addEventListener("mousemove",this.scrollEvent),this.container.addEventListener("touchmove",this.scrollEvent),this.scrollStart(a))};
LiteScroll.prototype._scroll=function(a){a.preventDefault();window.cancelAnimationFrame(this.scrollFrame);this.scrollFrame=window.requestAnimationFrame(function(){this._scrollFrame(a)}.bind(this))};
LiteScroll.prototype._scrollFrame=function(a){var b=this.calcTouchCoords(a),c=b.x-this.scrollInitMouseVec.x,b=b.y-this.scrollInitMouseVec.y;this.options.scrollLock&&!this.scrollLock&&(this.options.scrollX&&Math.abs(c)>this.options.scrollLockThreshold&&(this.scrollLock="x"),this.options.scrollY&&Math.abs(b)>this.options.scrollLockThreshold&&(this.scrollLock="y"));this.scrollTo(this.scrollInitVec.x+c,this.scrollInitVec.y+b,0,"linear");this.scroll(a)};
LiteScroll.prototype._scrollEnd=function(a){if(this.scrollEvent){window.cancelAnimationFrame(this.scrollFrame);var b=this.calcTouchCoords(a),c=b.x-this.scrollInitMouseVec.x,b=b.y-this.scrollInitMouseVec.y;if(this.options.momentum){var d=Date.now()-this.scrollBegin,c=c/d,b=b/d;this.scrollTo(this.x+Math.abs(c)*c/(2*this.options.momentumFalloff),this.y+Math.abs(b)*b/(2*this.options.momentumFalloff),Math.abs("x"===this.scrollLock||Math.abs(c)>Math.abs(b)?c:b)/this.options.momentumFalloff,"cubic-bezier(0.165, 0.840, 0.440, 1.000)",
this.options.snap?this.snapToNearest:null)}else this.options.snap&&this.snapToNearest();this.container.removeEventListener("mousemove",this.scrollEvent);this.container.removeEventListener("touchmove",this.scrollEvent);this.scrollLock=this.scrollEvent=null;this.scrollEnd(a)}};<commit_msg>Forgot to update min file<commit_after>/**
 * Lite Scroll
 *
 * @version    0.3.4
 * @author     Aiden Foxx
 * @license    MIT License
 * @copyright  2015 Aiden Foxx
 * @link       http://github.com/aidenfoxx
 * @twitter    @furiousfoxx
 */
function LiteScroll(a,b){if(!(this instanceof LiteScroll))return new LiteScroll(a,b);this.container=a;this.content=a.children[0];this.scrollFrame=this.scrollBegin=this.scrollEvent=this.scrollLock=this.scrollCallback=null;this.scrollInitVec={x:0,y:0};this.scrollInitMouseVec={x:0,y:0};this.childRect=this.contentRect=this.containerRect=this.resizeTimeout=null;this.y=this.x=0;this.options={scrollX:!1,scrollY:!0,snap:!1,snapSpeed:300,dynamicResize:!0,scrollLock:!0,scrollLockThreshold:20,momentum:!0,momentumFalloff:.006,
gpuAcceleration:!1};for(var c in b)this.options[c]=b[c];this.resizeCallback();this.bindEvents()}LiteScroll.prototype.scrollStart=function(a){};LiteScroll.prototype.scroll=function(a){};LiteScroll.prototype.scrollEnd=function(a){};LiteScroll.prototype.calcRelativePos=function(a,b){return{x:a-this.containerRect.left,y:b-this.containerRect.top}};
LiteScroll.prototype.calcTouchCoords=function(a){return this.calcRelativePos(a.changedTouches?a.changedTouches[0].pageX:a.pageX,a.changedTouches?a.changedTouches[0].pageY:a.pageY)};LiteScroll.prototype.clacPointDistance=function(a,b){var c=b.x-a.x,d=b.y-a.y;return Math.sqrt(c*c+d*d)};
LiteScroll.prototype.calcNearestChild=function(){for(var a=null,b=0,c=0,d=this.childRect.length;c<d;c++){var e=this.calcRelativePos(this.childRect[c].left,this.childRect[c].top);e.x=-e.x;e.y=-e.y;e=this.clacPointDistance(this,e);if(!c||e<a)a=e,b=c}return b};
LiteScroll.prototype.getChildRect=function(){var a=[],b=this.content.style.transform;this.content.style.transitionDuration="0ms";this.content.style.transform=this.content.style.webkitTransform="translate(0px, 0px)";for(var c=0,d=this.content.children.length;c<d;c++)a.push(this.content.children[c].getBoundingClientRect());this.content.style.transform=this.content.style.webkitTransform=b;return a};
LiteScroll.prototype.bindEvents=function(){0<navigator.maxTouchPoints?(this.container.addEventListener("pointerdown",this._scrollStart.bind(this)),document.addEventListener("pointerout",this._scrollEnd.bind(this))):0<navigator.msMaxTouchPoints&&(this.container.addEventListener("MSPointerDown",this._scrollStart.bind(this)),document.addEventListener("MSPointerOut",this._scrollEnd.bind(this)));this.container.addEventListener("mousedown",this._scrollStart.bind(this));this.container.addEventListener("touchstart",
this._scrollStart.bind(this));document.addEventListener("mouseup",this._scrollEnd.bind(this));document.addEventListener("touchend",this._scrollEnd.bind(this));document.addEventListener("touchcancel",this._scrollEnd.bind(this));this.options.dynamicResize&&window.addEventListener("resize",this.resize.bind(this))};LiteScroll.prototype.resize=function(){clearTimeout(this.resizeTimeout);this.resizeTimeout=setTimeout(function(){this.resizeCallback()}.bind(this),500)};
LiteScroll.prototype.resizeCallback=function(){this.containerRect=this.container.getBoundingClientRect();this.contentRect=this.content.getBoundingClientRect();this.childRect=this.getChildRect()};
LiteScroll.prototype.scrollTo=function(a,b,c,d,e){a=Math.round(a);b=Math.round(b);if(this.options.scrollX&&"y"!==this.scrollLock&&this.x!==a){var h=this.contentRect.width-this.containerRect.width;if(0<a||a<-h){var f=this.x-a;a=0<a?0:-h;f=Math.abs(this.x-a)/Math.abs(f)}this.x=a}if(this.options.scrollY&&"x"!==this.scrollLock&&this.y!==b){a=this.contentRect.height-this.containerRect.height;if(0<b||b<-a){var g=this.y-b;b=0<b?0:-a;g=Math.abs(this.y-b)/Math.abs(g)}this.y=b}!f&&g?c*=g:f&&!g?c*=f:f&&g&&(c*=
f<g?f:g);this.content.style.transform=this.content.style.webkitTransform="translate("+this.x+"px, "+this.y+"px)"+(this.gpuAcceleration?" translateZ(0px)":"");this.content.style.transitionDuration=c+"ms";this.content.style.transitionTimingFunction=d;clearTimeout(this.scrollCallback);e&&(this.scrollCallback=setTimeout(e.bind(this),c))};
LiteScroll.prototype.snapTo=function(a,b,c,d){if(!this.childRect[a])return!1;a=this.calcRelativePos(this.childRect[a].left,this.childRect[a].top);this.scrollTo(-a.x,-a.y,0<=b?b:this.options.snapSpeed,c?c:"cubic-bezier(0.1, 0.55, 0.1, 1)",d)};LiteScroll.prototype.snapToNearest=function(a,b,c){return this.snapTo(this.calcNearestChild(),a,b,c)};
LiteScroll.prototype._scrollStart=function(a){a.preventDefault();this.scrollEvent||(this.scrollBegin=Date.now(),this.scrollInitMouseVec=this.calcTouchCoords(a),this.scrollInitVec={x:this.x,y:this.y},this.scrollEvent=this._scroll.bind(this),this.container.addEventListener("mousemove",this.scrollEvent),this.container.addEventListener("touchmove",this.scrollEvent),this.scrollStart(a))};
LiteScroll.prototype._scroll=function(a){a.preventDefault();window.cancelAnimationFrame(this.scrollFrame);this.scrollFrame=window.requestAnimationFrame(function(){this._scrollFrame(a)}.bind(this))};
LiteScroll.prototype._scrollFrame=function(a){var b=this.calcTouchCoords(a),c=b.x-this.scrollInitMouseVec.x,b=b.y-this.scrollInitMouseVec.y;this.options.scrollLock&&!this.scrollLock&&(this.options.scrollX&&Math.abs(c)>this.options.scrollLockThreshold&&(this.scrollLock="x"),this.options.scrollY&&Math.abs(b)>this.options.scrollLockThreshold&&(this.scrollLock="y"));this.scrollTo(this.scrollInitVec.x+c,this.scrollInitVec.y+b,0,"linear");this.scroll(a)};
LiteScroll.prototype._scrollEnd=function(a){if(this.scrollEvent){window.cancelAnimationFrame(this.scrollFrame);var b=this.calcTouchCoords(a),c=b.x-this.scrollInitMouseVec.x,b=b.y-this.scrollInitMouseVec.y;if(this.options.momentum){var d=Date.now()-this.scrollBegin,c=c/d,b=b/d;this.scrollTo(this.x+Math.abs(c)*c/(2*this.options.momentumFalloff),this.y+Math.abs(b)*b/(2*this.options.momentumFalloff),Math.abs("x"===this.scrollLock||Math.abs(c)>Math.abs(b)?c:b)/this.options.momentumFalloff,"cubic-bezier(0.165, 0.840, 0.440, 1.000)",
this.options.snap?this.snapToNearest:null)}else this.options.snap&&this.snapToNearest();this.container.removeEventListener("mousemove",this.scrollEvent);this.container.removeEventListener("touchmove",this.scrollEvent);this.scrollLock=this.scrollEvent=null;this.scrollEnd(a)}};<|endoftext|>


<commit_before>// Not using arrow functions since this will also be used in the browser.
// http://caniuse.com/#feat=arrow-functions

(function () {
    'use strict';

    function Test(errs, helper) {
        this.helper = helper;
        // add `Error` so we can compare
        this.errors = errs.concat();
        this.errors.push(Error);
        this.ERR_MSG = 'err message';

        var self = this;
        // create instances for each custom error and Error
        this.instances = this.errors.map(function (Err) {
            try {
                return new Err(self.ERR_MSG);
            } catch (e) {
                return null;
            }
        });
        // get names for display purposes
        this.names = this.instances.map(function (e, index) {
            // if this custom error is not supported in the env, `e` will be
            // `null`. then we'll get the name from the object's name
            // property which is explicitly set for this purpose.
            return e ? e.name : (self.errors[index] ? self.errors[index].name : '-');
        });
        this.exec = helper.getTester(this.errors, this.instances);
    }

    Test.prototype.run = function () {
        var self = this;
        return [
            // first row is columns
            [''].concat(this.names),

            this.exec('e.name', function (E, e, s) { return e.name; }),
            this.exec('e.constructor.name', function (E, e, s) { return e.constructor.name; }),
            // this.exec('E.constructor.name', function (E, e, s) { return E.constructor.name; }),
            this.exec('e.constructor.name === e.name', function (E, e, s) { return e.constructor.name === e.name; }),
            this.exec('e.message === ERR_MSG', function (E, e, s) { return e.message === self.ERR_MSG; }),
            this.exec('typeof e === "object"', function (E, e, s) { return typeof e === 'object'; }),
            this.exec('typeof E === "function"', function (E, e, s) { return typeof E === 'function'; }),
            this.exec('getType(e) === "error"', function (E, e, s) { return self.helper.getType(e) === 'error'; }, true),
            this.exec('getType(E) === "function"', function (E, e, s) { return self.helper.getType(E) === 'function'; }),
            // this.exec('getPrototypeOf(E) === Function.prototype', function (E, e, s) { return Object.getPrototypeOf(E) === Function.prototype; }),
            // this.exec('getPrototypeOf(E) === Error.prototype', function (E, e, s) { return Object.getPrototypeOf(E) === Error.prototype; }),
            this.exec('getPrototypeOf(e) === Error.prototype', function (E, e, s) { return Object.getPrototypeOf(e) === Error.prototype; }, true),
            this.exec('getPrototypeOf(e) === E.prototype', function (E, e, s) { return Object.getPrototypeOf(e) === E.prototype; }),
            // this.exec('getPrototypeOf(E) === E.prototype', function (E, e, s) { return Object.getPrototypeOf(E) === E.prototype; }),
            // this.exec('getPrototypeOf(E) === getPrototypeOf(e)', function (E, e, s) { return Object.getPrototypeOf(E) === Object.getPrototypeOf(e); }),
            this.exec('e instanceof E', function (E, e, s) { return e instanceof E; }),
            this.exec('e instanceof Error', function (E, e, s) { return e instanceof Error; }),
            this.exec('e.toString()', function (E, e, s) { return typeof e.toString === 'function' && e.toString().indexOf(e.name) >= 0; }),
            this.exec('e.stack has name', function (E, e, s) { return s.indexOf(e.name) >= 0; }),
            this.exec('e.stack has ERR_MSG', function (E, e, s) { return s.indexOf(self.ERR_MSG) >= 0; }, true),
            this.exec('e.stack has line info', function (E, e, s) { return s.indexOf('/test.js:') >= 0; }),
            this.exec('e.stack has no extra line', function (E, e, s) { return s.split('\n')[1].indexOf(e.name) < 0; }, true),
            this.exec('getPrototypeOf(E) === E.__proto__', function (E, e, s) { return Error.__proto__ && Object.getPrototypeOf(E) === E.__proto__; }, true),
            this.exec('getPrototypeOf(e) === e.__proto__', function (E, e, s) { return Error.__proto__ && Object.getPrototypeOf(e) === e.__proto__; }, true)
        ];
    };

    Test.prototype.logStackSamples = function () {
        return this.instances.map(function (e) {
            if (e === null) return 'NO SUPPORT';
            var stack = '';
            try {
                throw e;
            } catch (err) {
                stack = err.stack;
            }
            return stack;
        });
    };

    if (typeof module === 'object' && typeof module.exports === 'object') {
        module.exports = Test;
    } else {
        window.Test = Test;
    }

})();

<commit_msg>fix when stack is null<commit_after>// Not using arrow functions since this will also be used in the browser.
// http://caniuse.com/#feat=arrow-functions

(function () {
    'use strict';

    function Test(errs, helper) {
        this.helper = helper;
        // add `Error` so we can compare
        this.errors = errs.concat();
        this.errors.push(Error);
        this.ERR_MSG = 'err message';

        var self = this;
        // create instances for each custom error and Error
        this.instances = this.errors.map(function (Err) {
            try {
                return new Err(self.ERR_MSG);
            } catch (e) {
                return null;
            }
        });
        // get names for display purposes
        this.names = this.instances.map(function (e, index) {
            // if this custom error is not supported in the env, `e` will be
            // `null`. then we'll get the name from the object's name
            // property which is explicitly set for this purpose.
            return e ? e.name : (self.errors[index] ? self.errors[index].name : '-');
        });
        this.exec = helper.getTester(this.errors, this.instances);
    }

    Test.prototype.run = function () {
        var self = this;
        return [
            // first row is columns
            [''].concat(this.names),

            this.exec('e.name', function (E, e, s) { return e.name; }),
            this.exec('e.constructor.name', function (E, e, s) { return e.constructor.name; }),
            // this.exec('E.constructor.name', function (E, e, s) { return E.constructor.name; }),
            this.exec('e.constructor.name === e.name', function (E, e, s) { return e.constructor.name === e.name; }),
            this.exec('e.message === ERR_MSG', function (E, e, s) { return e.message === self.ERR_MSG; }),
            this.exec('typeof e === "object"', function (E, e, s) { return typeof e === 'object'; }),
            this.exec('typeof E === "function"', function (E, e, s) { return typeof E === 'function'; }),
            this.exec('getType(e) === "error"', function (E, e, s) { return self.helper.getType(e) === 'error'; }, true),
            this.exec('getType(E) === "function"', function (E, e, s) { return self.helper.getType(E) === 'function'; }),
            // this.exec('getPrototypeOf(E) === Function.prototype', function (E, e, s) { return Object.getPrototypeOf(E) === Function.prototype; }),
            // this.exec('getPrototypeOf(E) === Error.prototype', function (E, e, s) { return Object.getPrototypeOf(E) === Error.prototype; }),
            this.exec('getPrototypeOf(e) === Error.prototype', function (E, e, s) { return Object.getPrototypeOf(e) === Error.prototype; }, true),
            this.exec('getPrototypeOf(e) === E.prototype', function (E, e, s) { return Object.getPrototypeOf(e) === E.prototype; }),
            // this.exec('getPrototypeOf(E) === E.prototype', function (E, e, s) { return Object.getPrototypeOf(E) === E.prototype; }),
            // this.exec('getPrototypeOf(E) === getPrototypeOf(e)', function (E, e, s) { return Object.getPrototypeOf(E) === Object.getPrototypeOf(e); }),
            this.exec('e instanceof E', function (E, e, s) { return e instanceof E; }),
            this.exec('e instanceof Error', function (E, e, s) { return e instanceof Error; }),
            this.exec('e.toString()', function (E, e, s) { return typeof e.toString === 'function' && e.toString().indexOf(e.name) >= 0; }),
            this.exec('e.stack has name', function (E, e, s) { return s.indexOf(e.name) >= 0; }),
            this.exec('e.stack has ERR_MSG', function (E, e, s) { return s.indexOf(self.ERR_MSG) >= 0; }, true),
            this.exec('e.stack has line info', function (E, e, s) { return s.indexOf('/test.js:') >= 0; }),
            this.exec('e.stack has no extra line', function (E, e, s) { var sp = s.split('\n'); return sp.length > 1 && sp[1].indexOf(e.name) < 0; }, true),
            this.exec('getPrototypeOf(E) === E.__proto__', function (E, e, s) { return Error.__proto__ && Object.getPrototypeOf(E) === E.__proto__; }, true),
            this.exec('getPrototypeOf(e) === e.__proto__', function (E, e, s) { return Error.__proto__ && Object.getPrototypeOf(e) === e.__proto__; }, true)
        ];
    };

    Test.prototype.logStackSamples = function () {
        return this.instances.map(function (e) {
            if (e === null) return 'NO SUPPORT';
            var stack = (e.constructor ? e.constructor.name : '(unknown)') + ' stack sample:\n';
            try {
                throw e;
            } catch (err) {
                stack += err.stack;
            }
            return stack;
        });
    };

    if (typeof module === 'object' && typeof module.exports === 'object') {
        module.exports = Test;
    } else {
        window.Test = Test;
    }

})();

<|endoftext|>


<commit_before>import expect from 'expect';
import RestApi, {RestfulAPI} from '../index.js';

const baseUrl = 'http://jsonplaceholder.typicode.com';
const NOT_FOUND_ERROR = 404;

describe('main plug-in test', function () {

	this.timeout(15000);

	it('should be initialized by default', () => {
		expect(RestfulAPI).toExist();
	});

	it('should create a new instance of class RestfulAPI', () => {
		expect(new RestfulAPI()).toExist();
	});

	it('should include error handler', () => {
		let errorResponseHandler = () => {
		};
		let restfulAPI = new RestfulAPI({errorResponseHandler});
		expect(restfulAPI.errorResponseHandler).toBe(errorResponseHandler);
	});

	it('RestApi instance should exist', () => {
		expect(RestApi).toExist();
	});

	it('should get response from server', done => {
		RestApi.fetch(`${baseUrl}/users`).then(response => {
			expect(response.length).toExist().toBeMoreThan(0);
			done();
		});
	});

	it('should get response from server', done => {
		RestApi.get(`${baseUrl}/users`).then(response => {
			expect(response.length).toExist().toBeMoreThan(0);
			done();
		});
	});

	it('should post data to server', done => {
		RestApi.post(`${baseUrl}/posts`, {
			data: {
				title: 'restful-js'
			}
		}).then(response => {
			expect(response).toExist().toIncludeKey('id').toIncludeKey('data');
			done();
		});
	});

	it('should post data to server with FormData object', done => {
		let formData = new FormData();
		if (formData.set) { // to support FF < 39.0
			formData.set('upload', JSON.stringify({
				data: {
					title: 'restful-js'
				}
			}));
			RestApi.post(`${baseUrl}/posts`, formData).then(response => {
				expect(response).toExist().toIncludeKey('id');
				done();
			});
		}
		else {done();}
	});

	it('should update data on server', done => {
		RestApi.put(`${baseUrl}/posts/1`, {
			data: {
				id: 1,
				title: 'restful-js is awesome'
			}
		}).then(response => {
			expect(response).toExist().toIncludeKey('id');
			done();
		});
	});

	it('should delete data on server', done => {
		RestApi.destroy(`${baseUrl}/posts/1`).then(response => {
			expect(response).toExist();
			done();
		});
	});

	it('should throw error without error handling', done => {
		RestApi.fetch(`${baseUrl}/non/exist/resource`).then(() => {
		}, error => {
			expect(error.status).toExist().toEqual(NOT_FOUND_ERROR);
			done();
		});
	});

	it('should throw error with error handling', done => {
		let errorResponseHandler = (xhr/*, textStatus, errorThrown*/) => {
			expect(xhr.status).toExist().toEqual(NOT_FOUND_ERROR);
			done();
		};
		let restfulAPI = new RestfulAPI({errorResponseHandler});
		restfulAPI.fetch(`${baseUrl}/non/exist/resource`);
	});

	it('should call ajax start event', done => {
		const ajaxStartHandler = function () {
			done();
		};
		new RestfulAPI({ajaxStartHandler}).get(`${baseUrl}/users`);
	});

	it('should call ajax stop event', done => {
		const ajaxStopHandler = function () {
			done();
		};
		new RestfulAPI({ajaxStopHandler}).get(`${baseUrl}/users`);
	});

	it('should expose jQuery to the out side', () => {
		expect(RestApi.$).toExist();
	});

});
<commit_msg>set timeout to 5 sec.<commit_after>import expect from 'expect';
import RestApi, {RestfulAPI} from '../index.js';

const baseUrl = 'http://jsonplaceholder.typicode.com';
const NOT_FOUND_ERROR = 404;

describe('main plug-in test', function () {

	this.timeout(5000);

	it('should be initialized by default', () => {
		expect(RestfulAPI).toExist();
	});

	it('should create a new instance of class RestfulAPI', () => {
		expect(new RestfulAPI()).toExist();
	});

	it('should include error handler', () => {
		let errorResponseHandler = () => {
		};
		let restfulAPI = new RestfulAPI({errorResponseHandler});
		expect(restfulAPI.errorResponseHandler).toBe(errorResponseHandler);
	});

	it('RestApi instance should exist', () => {
		expect(RestApi).toExist();
	});

	it('should get response from server', done => {
		RestApi.fetch(`${baseUrl}/users`).then(response => {
			expect(response.length).toExist().toBeMoreThan(0);
			done();
		});
	});

	it('should get response from server', done => {
		RestApi.get(`${baseUrl}/users`).then(response => {
			expect(response.length).toExist().toBeMoreThan(0);
			done();
		});
	});

	it('should post data to server', done => {
		RestApi.post(`${baseUrl}/posts`, {
			data: {
				title: 'restful-js'
			}
		}).then(response => {
			expect(response).toExist().toIncludeKey('id').toIncludeKey('data');
			done();
		});
	});

	it('should post data to server with FormData object', done => {
		let formData = new FormData();
		if (formData.set) { // to support FF < 39.0
			formData.set('upload', JSON.stringify({
				data: {
					title: 'restful-js'
				}
			}));
			RestApi.post(`${baseUrl}/posts`, formData).then(response => {
				expect(response).toExist().toIncludeKey('id');
				done();
			});
		}
		else {done();}
	});

	it('should update data on server', done => {
		RestApi.put(`${baseUrl}/posts/1`, {
			data: {
				id: 1,
				title: 'restful-js is awesome'
			}
		}).then(response => {
			expect(response).toExist().toIncludeKey('id');
			done();
		});
	});

	it('should delete data on server', done => {
		RestApi.destroy(`${baseUrl}/posts/1`).then(response => {
			expect(response).toExist();
			done();
		});
	});

	it('should throw error without error handling', done => {
		RestApi.fetch(`${baseUrl}/non/exist/resource`).then(() => {
		}, error => {
			expect(error.status).toExist().toEqual(NOT_FOUND_ERROR);
			done();
		});
	});

	it('should throw error with error handling', done => {
		let errorResponseHandler = (xhr/*, textStatus, errorThrown*/) => {
			expect(xhr.status).toExist().toEqual(NOT_FOUND_ERROR);
			done();
		};
		let restfulAPI = new RestfulAPI({errorResponseHandler});
		restfulAPI.fetch(`${baseUrl}/non/exist/resource`);
	});

	it('should call ajax start event', done => {
		const ajaxStartHandler = function () {
			done();
		};
		new RestfulAPI({ajaxStartHandler}).get(`${baseUrl}/users`);
	});

	it('should call ajax stop event', done => {
		const ajaxStopHandler = function () {
			done();
		};
		new RestfulAPI({ajaxStopHandler}).get(`${baseUrl}/users`);
	});

	it('should expose jQuery to the out side', () => {
		expect(RestApi.$).toExist();
	});

});
<|endoftext|>