<commit_before>'use strict';

var readdir = require('../../');
var dir = require('../fixtures/dir');
var expect = require('chai').expect;
var through2 = require('through2');
var fs = require('fs');

describe('Stream API', function () {
  it('should be able to pipe to other streams as a Buffer', function (done) {
    var allData = [];

    readdir.stream('test/dir')
      .pipe(through2(function (data, enc, next) {
        try {
          // By default, the data is streamed as a Buffer
          expect(data).to.be.an.instanceOf(Buffer);

          // Buffer.toString() returns the file name
          allData.push(data.toString());

          next(null, data);
        }
        catch (e) {
          next(e);
        }
      }))
      .on('finish', function () {
        try {
          expect(allData).to.have.same.members(dir.shallow.data);
          done();
        }
        catch (e) {
          done(e);
        }
      })
      .on('error', function (err) {
        done(err);
      });
  });

  it('should be able to pipe to other streams in "object mode"', function (done) {
    var allData = [];

    readdir.stream('test/dir')
      .pipe(through2({ objectMode: true }, function (data, enc, next) {
        try {
          // In "object mode", the data is a string
          expect(data).to.be.a('string');

          allData.push(data);
          next(null, data);
        }
        catch (e) {
          next(e);
        }
      }))
      .on('finish', function () {
        try {
          expect(allData).to.have.same.members(dir.shallow.data);
          done();
        }
        catch (e) {
          done(e);
        }
      })
      .on('error', function (err) {
        done(err);
      });
  });

  it('should be able to pipe fs.Stats to other streams in "object mode"', function (done) {
    var allData = [];

    readdir.stream.stat('test/dir')
      .pipe(through2({ objectMode: true }, function (data, enc, next) {
        try {
          // The data is an fs.Stats object
          expect(data).to.be.an('object');
          expect(data).to.be.an.instanceOf(fs.Stats);

          allData.push(data.path);
          next(null, data);
        }
        catch (e) {
          next(e);
        }
      }))
      .on('finish', function () {
        try {
          expect(allData).to.have.same.members(dir.shallow.data);
          done();
        }
        catch (e) {
          done(e);
        }
      })
      .on('error', done);
  });

  it('should be able to pause & resume the stream', function (done) {
    var allData = [];

    var stream = readdir.stream('test/dir')
      .on('data', function (data) {
        allData.push(data);

        // The stream should not be paused
        expect(stream.isPaused()).to.be.false;

        if (allData.length === 3) {
          // Pause for one second
          stream.pause();
          setTimeout(function () {
            try {
              // The stream should still be paused
              expect(stream.isPaused()).to.be.true;

              // The array should still only contain 3 items
              expect(allData).to.have.lengthOf(3);

              // Read the rest of the stream
              stream.resume();
            }
            catch (e) {
              done(e);
            }
          }, 1000);
        }
      })
      .on('end', function () {
        expect(allData).to.have.same.members(dir.shallow.data);
        done();
      })
      .on('error', done);
  });

  it('should be able to use "readable" and "read"', function (done) {
    var allData = [];
    var nullCount = 0;

    var stream = readdir.stream('test/dir')
      .on('readable', function () {
        // Manually read the next chunk of data
        var data = stream.read();

        if (data === null) {
          // The stream is done
          nullCount++;
        }
        else {
          // The data should be a string (the file name)
          expect(data).to.be.a('string').and.not.empty;
          allData.push(data);
        }
      })
      .on('end', function () {
        // stream.read() should only return null once
        expect(nullCount).to.equal(1);

        expect(allData).to.have.same.members(dir.shallow.data);
        done();
      })
      .on('error', done);
  });

  it('should be able to subscribe to custom events instead of "data"', function (done) {
    var allFiles = [];
    var allSubdirs = [];

    readdir.stream('test/dir')
      .resume()           // <--- Calling "resume" is required, since we're not handling the "data" event
      .on('file', function (filename) {
        expect(filename).to.be.a('string').and.not.empty;
        allFiles.push(filename);
      })
      .on('directory', function (subdir) {
        expect(subdir).to.be.a('string').and.not.empty;
        allSubdirs.push(subdir);
      })
      .on('end', function () {
        expect(allFiles).to.have.same.members(dir.shallow.files);
        expect(allSubdirs).to.have.same.members(dir.shallow.dirs);
        done();
      })
      .on('error', done);
  });

  it('should handle errors that occur in the "data" event listener', function (done) {
    testErrorHandling('data', dir.shallow.data, 7, done);
  });

  it('should handle errors that occur in the "file" event listener', function (done) {
    testErrorHandling('file', dir.shallow.files, 3, done);
  });

  it('should handle errors that occur in the "directory" event listener', function (done) {
    testErrorHandling('directory', dir.shallow.dirs, 2, done);
  });

  it('should handle errors that occur in the "symlink" event listener', function (done) {
    testErrorHandling('symlink', dir.shallow.symlinks, 5, done);
  });

  function testErrorHandling (eventName, expected, expectedErrors, done) {
    var errors = [], data = [];
    var stream = readdir.stream('test/dir');

    // Capture all errors
    stream.on('error', function (error) {
      errors.push(error);
    });

    stream.on(eventName, function (path) {
      data.push(path);

      if (path.indexOf('.txt') >= 0 || path.indexOf('dir-') >= 0) {
        throw new Error('Epic Fail!!!');
      }
      else {
        return true;
      }
    });

    stream.on('end', function () {
      try {
        // Make sure the correct number of errors were thrown
        expect(errors.length).to.equal(expectedErrors);
        errors.forEach(function (error) {
          expect(error.message).to.equal('Epic Fail!!!');
        });

        // All of the events should have still been emitted, despite the errors
        expect(data).to.have.same.members(expected);

        done();
      }
      catch (e) {
        done(e);
      }
    });

    stream.resume();
  }
});
<commit_msg>fixed tests that were failing in Node v0.10<commit_after>'use strict';

var readdir = require('../../');
var dir = require('../fixtures/dir');
var expect = require('chai').expect;
var through2 = require('through2');
var fs = require('fs');

var isNode10 = process.version.substr(0, 5) === 'v0.10';

describe('Stream API', function () {
  it('should be able to pipe to other streams as a Buffer', function (done) {
    var allData = [];

    readdir.stream('test/dir')
      .pipe(through2(function (data, enc, next) {
        try {
          // By default, the data is streamed as a Buffer
          expect(data).to.be.an.instanceOf(Buffer);

          // Buffer.toString() returns the file name
          allData.push(data.toString());

          next(null, data);
        }
        catch (e) {
          next(e);
        }
      }))
      .on('finish', function () {
        try {
          expect(allData).to.have.same.members(dir.shallow.data);
          done();
        }
        catch (e) {
          done(e);
        }
      })
      .on('error', function (err) {
        done(err);
      });
  });

  it('should be able to pipe to other streams in "object mode"', function (done) {
    var allData = [];

    readdir.stream('test/dir')
      .pipe(through2({ objectMode: true }, function (data, enc, next) {
        try {
          // In "object mode", the data is a string
          expect(data).to.be.a('string');

          allData.push(data);
          next(null, data);
        }
        catch (e) {
          next(e);
        }
      }))
      .on('finish', function () {
        try {
          expect(allData).to.have.same.members(dir.shallow.data);
          done();
        }
        catch (e) {
          done(e);
        }
      })
      .on('error', function (err) {
        done(err);
      });
  });

  it('should be able to pipe fs.Stats to other streams in "object mode"', function (done) {
    var allData = [];

    readdir.stream.stat('test/dir')
      .pipe(through2({ objectMode: true }, function (data, enc, next) {
        try {
          // The data is an fs.Stats object
          expect(data).to.be.an('object');
          expect(data).to.be.an.instanceOf(fs.Stats);

          allData.push(data.path);
          next(null, data);
        }
        catch (e) {
          next(e);
        }
      }))
      .on('finish', function () {
        try {
          expect(allData).to.have.same.members(dir.shallow.data);
          done();
        }
        catch (e) {
          done(e);
        }
      })
      .on('error', done);
  });

  it('should be able to pause & resume the stream', function (done) {
    var allData = [];

    var stream = readdir.stream('test/dir')
      .on('data', function (data) {
        allData.push(data);

        // stream.isPaused() doesn't exist in Node v0.10
        if (!isNode10) {
          // The stream should not be paused
          expect(stream.isPaused()).to.be.false;
        }

        if (allData.length === 3) {
          // Pause for one second
          stream.pause();
          setTimeout(function () {
            try {
              // stream.isPaused() doesn't exist in Node v0.10
              if (!isNode10) {
                // The stream should still be paused
                expect(stream.isPaused()).to.be.true;
              }

              // The array should still only contain 3 items
              expect(allData).to.have.lengthOf(3);

              // Read the rest of the stream
              stream.resume();
            }
            catch (e) {
              done(e);
            }
          }, 1000);
        }
      })
      .on('end', function () {
        expect(allData).to.have.same.members(dir.shallow.data);
        done();
      })
      .on('error', done);
  });

  it('should be able to use "readable" and "read"', function (done) {
    var allData = [];
    var nullCount = 0;

    var stream = readdir.stream('test/dir')
      .on('readable', function () {
        // Manually read the next chunk of data
        var data = stream.read();

        if (data === null) {
          // The stream is done
          nullCount++;
        }
        else {
          // The data should be a string (the file name)
          expect(data).to.be.a('string').and.not.empty;
          allData.push(data);
        }
      })
      .on('end', function () {
        if (isNode10) {
          // In Node v0.10, stream.read() always returns data
          expect(nullCount).to.equal(0);
        }
        else {
          // stream.read() should only return null once
          expect(nullCount).to.equal(1);
        }

        expect(allData).to.have.same.members(dir.shallow.data);
        done();
      })
      .on('error', done);
  });

  it('should be able to subscribe to custom events instead of "data"', function (done) {
    var allFiles = [];
    var allSubdirs = [];

    var stream = readdir.stream('test/dir');

    // Calling "resume" is required, since we're not handling the "data" event
    stream.resume();

    stream
      .on('file', function (filename) {
        expect(filename).to.be.a('string').and.not.empty;
        allFiles.push(filename);
      })
      .on('directory', function (subdir) {
        expect(subdir).to.be.a('string').and.not.empty;
        allSubdirs.push(subdir);
      })
      .on('end', function () {
        expect(allFiles).to.have.same.members(dir.shallow.files);
        expect(allSubdirs).to.have.same.members(dir.shallow.dirs);
        done();
      })
      .on('error', done);
  });

  it('should handle errors that occur in the "data" event listener', function (done) {
    testErrorHandling('data', dir.shallow.data, 7, done);
  });

  it('should handle errors that occur in the "file" event listener', function (done) {
    testErrorHandling('file', dir.shallow.files, 3, done);
  });

  it('should handle errors that occur in the "directory" event listener', function (done) {
    testErrorHandling('directory', dir.shallow.dirs, 2, done);
  });

  it('should handle errors that occur in the "symlink" event listener', function (done) {
    testErrorHandling('symlink', dir.shallow.symlinks, 5, done);
  });

  function testErrorHandling (eventName, expected, expectedErrors, done) {
    var errors = [], data = [];
    var stream = readdir.stream('test/dir');

    // Capture all errors
    stream.on('error', function (error) {
      errors.push(error);
    });

    stream.on(eventName, function (path) {
      data.push(path);

      if (path.indexOf('.txt') >= 0 || path.indexOf('dir-') >= 0) {
        throw new Error('Epic Fail!!!');
      }
      else {
        return true;
      }
    });

    stream.on('end', function () {
      try {
        // Make sure the correct number of errors were thrown
        expect(errors.length).to.equal(expectedErrors);
        errors.forEach(function (error) {
          expect(error.message).to.equal('Epic Fail!!!');
        });

        // All of the events should have still been emitted, despite the errors
        expect(data).to.have.same.members(expected);

        done();
      }
      catch (e) {
        done(e);
      }
    });

    stream.resume();
  }
});
<|endoftext|>


<commit_before>// Dep: [lawnchair]/lawnchair
// Dep: [KadOH]/core/eventemitter
// Dep: [KadOH]/globals
// Dep: [KadOH]/peer
// Dep: [KadOH]/core/deferred
// Dep: [KadOH]/storage/basicstorage

(function(exports, Lawnchair) {

  var KadOH        = exports,
      EventEmitter = KadOH.core.EventEmitter,
      globals      = KadOH.globals,
      Peer         = KadOH.Peer,
      Deferred     = KadOH.core.Deferred,
      BasicStorage = KadOH.storage.BasicStorage;

  if (!Lawnchair) {
    KadOH.log.warn('Lawnchair not defined : non-persisant basic storage');
    Lawnchair = BasicStorage;
  }

  KadOH.ValueManagement = EventEmitter.extend({

    /**
     * Instanciate a new value management.
     *
     * @constructs
     * @param  {Object} node    The node instance on which the value mangement depends.
     * @param  {Object} [options] Some configuration options..
     * @param  {Boolean} [options.recover = true] If true, try to recover the last session that
     *                                    coresponds to the address/nodeID. If false, session is
     *                                    destructed and a new one is created.
     */
    initialize: function(node, options) {
      this.supr();
      this._node = node;

      var config = this.config = {
        recover: true
      };
      for (var option in options) {
        config[option] = options[option];
      }

      var self = this;
      //TODO : recover last session storage
      this._store = new Lawnchair({
        name   : ['KadOH', node.getID(), node.getAddress()].join('|'),
        record : 'KeyValue'
      }, function() {});

      if (config.recover) {
        this._recover();
      } else {
        this._store.nuke();
      }
    },

    /**
     * Store the given key/value in the storage. Provide an expirimation time.
     * Return ta deferred object representig the state of the store (resolved : OK, rejected : not OK).
     *
     * In the background, timers for republish and expiration are started.
     * For the xpiration time : negative value or not set : no expiration.
     *
     * Key/value are stored as object with properties :
     *   key   - the key
     *   value - the value that coresspond to the key (null if not found)
     *   exp   - expiration date (null or negative if unlimited)
     *   rep   - next republish date
     *
     * @public
     * @see  Deferred
     *
     * @param  {String}   key   the key associated to the value
     * @param  {*}        value the value of the key value
     * @param  {Integer}  [exp = -1]   timestamp for the expiration date (UTC in ms). If negative value or not set : no expiration.
     * @return {Deferred} a deferred object representing the state of the store
     */

    save: function(key, value, exp) {
      var def = new Deferred();

      var KeyValue = {
        key   : key,
        value : value
      };

      var now = +(new Date());

      //set republish date
      KeyValue.rep =  now + this._repTime;

      //check expiration time : negative value means infinite.
      KeyValue.exp = exp || -1;

      if(exp <= now) {
        KeyValue.now = now;
        this.emit('fail store', 'key-value already expired', KeyValue);
        def.reject('key-value already expired');
        return def;
      }

      //set the timers
      this._setRepTimout(KeyValue, this._repTime);
      this._setExpTimout(KeyValue, KeyValue.exp - now);

      //and save
      this._store.save(KeyValue, function(obj) {
        def.resolve(obj);
      });

      return def;
    },

    /**
     * Retrieve the value of the key.
     *
     * To catch the result, there is 2 ways :
     *    - provide a callback function that will be called with value and
     *    expiration date as arguments.
     *    - handle the defered object that is returned, by this methods. If
     *    result, value and expiration date are passed to the success calback
     *    and if no result, the errback is called.
     *
     * Are passed as arguments of the callbak functions:
     *   value - the value that coresspond to the key (null if not found)
     *   exp   - expiration date (null or negative if unlimited)
     *
     * @see  Deferred
     * @public
     *
     * @param  {String}   key      the key associated to the value
     * @param  {Function} [callback] callback function
     * @param  {Object}   [scope = this ValueManagement obejct] the scope to apply to the callback function (by default : the instance of ValuManagement)
     * @return {Deferred} a deferred object representing the state of the retrieve
     */

    retrieve: function(key, callback, scope) {
      var def = new Deferred();

      scope = scope || this;
      this._store.get(key, function(obj) {
        if(obj === null) {
          if (callback) callback.call(scope, null);
          def.reject();
        }
        else {
          obj.exp = obj.exp < 0 ? null : obj.exp;
          if (callback) callback.call(scope, obj.value, obj.exp);
          def.resolve(obj.value, obj.exp);
        }
      });
      return def;
    },

    /**
     * Recover the last stored session.
     *
     * @private
     */
    _recover: function() {
      var now = + (new Date());
      var self = this;

      this._store.each(function(kv){
        try {
          if(kv.exp >= 0 && kv.exp <= now) {
            self._store.remove(kv.key);
            return;
          }
          self._setExpTimout(kv,kv.exp - now);

          if(typeof kv.rep == 'undefined' || kv.exp <= now) {
            self._republish(kv);
            kv.rep =  now + self._repTime;
            self._store.save(kv);
          }

          self._setRepTimout(kv, kv.rep - now);

        } catch(e) {
          self._store.remove(kv.key);
        }
      });
    },

    /**
     * Reset a timeout for republish of the given Key/Value
     *
     * @private
     * @param {[type]} kv      Key/Value
     * @param {[type]} timeout the timeout
     */
    _setRepTimout: function(kv, timeout) {
      setTimeout(function(kv, self) {
        if(typeof kv == 'undefined') return; //in case of

        //check if it has already expired or if the timer is an old one
        var now = +(new Date());
        var hasExp = (typeof kv.exp == 'undefined' || kv.exp === null || kv.exp <0) ? false : (kv.exp < now);
        var notYet = (kv.rep > now);
        if(hasExp || notYet) return;

        self._republish(kv);
      }, timeout, kv, this);
      return this;
    },

    /**
     * Time between 2 republish processes of a stored value.
     * By default, the value is the TIMEOUT_REPUBLISH global constant.
     *
     * @private
     * @type {Integer}
     */
    _repTime : globals.TIMEOUT_REPUBLISH,

    /**
     * Make a key/value being republished by calling the `republish` method of node instance.
     *
     * Before it checks if key/value is still existing. Reset a new timer.
     *
     * @param  {Object} kv the key/value object to republish
     * @return {Object} this
     */
    _republish: function(kv) {
      var self = this;
      //check before if the key/value still exists
        this._store.exists(kv.key, function(exists) {
          if(exists) {
            //call node's republish method
            self._node.republish(kv.key, kv.value, kv.exp);

            //reset republish date
            var now = +(new Date());
            kv.rep = now + this._repTime;

            //reset a timer
            self._setRepTimout(kv, self._repTime);

            //sore it
            self._store.save(kv);

          }
        });
      return this;
    },

    /**
     * Reset a timeout for expiration of the given Key/Value.
     * If the Key/Value has a negative expiration date (infinite), nothing is done.
     *
     * @private
     * @param {[type]} kv      Key/Value
     * @param {[type]} timeout the timeout
     * @return this
     */
    _setExpTimout: function(kv, timeout) {
      if(kv.exp >= 0) {
        setTimeout(function(kv, self) {
          if(typeof kv == 'undefined') return; //in case of

          //check if it has already expired (old timer)
          var now = +(new Date());
          var hasExp = (typeof kv.exp == 'undefined' || kv.exp === null || kv.exp <0) ? false : (kv.exp < now);
          if(! hasExp) return;

          self._expire(kv);
        }, timeout, kv, this);
      }
      return this;
    },

    /**
     * Make a key/value expire. Before check if stil exists.
     *
     * @private
     * @param  {Object} kv the key/value to make expire
     * @return {Object} this
     */
    _expire: function(kv) {
      var self = this;
      //check before if the key/value still exists
        this._store.exists(kv.key, function(exists) {
          if(exists) {
            self._store.remove(kv.key);
            self.emit('expire', kv);
          }
        });
      return this;
    }

  });

})('object' === typeof module ? module.exports : (this.KadOH = this.KadOH || {}),
   'undefined' == typeof Lawnchair ? undefined : Lawnchair);<commit_msg>recover session was done<commit_after>// Dep: [lawnchair]/lawnchair
// Dep: [KadOH]/core/eventemitter
// Dep: [KadOH]/globals
// Dep: [KadOH]/peer
// Dep: [KadOH]/core/deferred
// Dep: [KadOH]/storage/basicstorage

(function(exports, Lawnchair) {

  var KadOH        = exports,
      EventEmitter = KadOH.core.EventEmitter,
      globals      = KadOH.globals,
      Peer         = KadOH.Peer,
      Deferred     = KadOH.core.Deferred,
      BasicStorage = KadOH.storage.BasicStorage;

  if (!Lawnchair) {
    KadOH.log.warn('Lawnchair not defined : non-persisant basic storage');
    Lawnchair = BasicStorage;
  }

  KadOH.ValueManagement = EventEmitter.extend({

    /**
     * Instanciate a new value management.
     *
     * @constructs
     * @param  {Object} node    The node instance on which the value mangement depends.
     * @param  {Object} [options] Some configuration options..
     * @param  {Boolean} [options.recover = true] If true, try to recover the last session that
     *                                    coresponds to the address/nodeID. If false, session is
     *                                    destructed and a new one is created.
     */
    initialize: function(node, options) {
      this.supr();
      this._node = node;

      var config = this.config = {
        recover: true
      };
      for (var option in options) {
        config[option] = options[option];
      }

      var self = this;
      this._store = new Lawnchair({
        name   : ['KadOH', node.getID(), node.getAddress()].join('|'),
        record : 'KeyValue'
      }, function() {});

      if (config.recover) {
        this._recover();
      } else {
        this._store.nuke();
      }
    },

    /**
     * Store the given key/value in the storage. Provide an expirimation time.
     * Return ta deferred object representig the state of the store (resolved : OK, rejected : not OK).
     *
     * In the background, timers for republish and expiration are started.
     * For the xpiration time : negative value or not set : no expiration.
     *
     * Key/value are stored as object with properties :
     *   key   - the key
     *   value - the value that coresspond to the key (null if not found)
     *   exp   - expiration date (null or negative if unlimited)
     *   rep   - next republish date
     *
     * @public
     * @see  Deferred
     *
     * @param  {String}   key   the key associated to the value
     * @param  {*}        value the value of the key value
     * @param  {Integer}  [exp = -1]   timestamp for the expiration date (UTC in ms). If negative value or not set : no expiration.
     * @return {Deferred} a deferred object representing the state of the store
     */

    save: function(key, value, exp) {
      var def = new Deferred();

      var KeyValue = {
        key   : key,
        value : value
      };

      var now = +(new Date());

      //set republish date
      KeyValue.rep =  now + this._repTime;

      //check expiration time : negative value means infinite.
      KeyValue.exp = exp || -1;

      if(exp <= now) {
        KeyValue.now = now;
        this.emit('fail store', 'key-value already expired', KeyValue);
        def.reject('key-value already expired');
        return def;
      }

      //set the timers
      this._setRepTimout(KeyValue, this._repTime);
      this._setExpTimout(KeyValue, KeyValue.exp - now);

      //and save
      this._store.save(KeyValue, function(obj) {
        def.resolve(obj);
      });

      return def;
    },

    /**
     * Retrieve the value of the key.
     *
     * To catch the result, there is 2 ways :
     *    - provide a callback function that will be called with value and
     *    expiration date as arguments.
     *    - handle the defered object that is returned, by this methods. If
     *    result, value and expiration date are passed to the success calback
     *    and if no result, the errback is called.
     *
     * Are passed as arguments of the callbak functions:
     *   value - the value that coresspond to the key (null if not found)
     *   exp   - expiration date (null or negative if unlimited)
     *
     * @see  Deferred
     * @public
     *
     * @param  {String}   key      the key associated to the value
     * @param  {Function} [callback] callback function
     * @param  {Object}   [scope = this ValueManagement obejct] the scope to apply to the callback function (by default : the instance of ValuManagement)
     * @return {Deferred} a deferred object representing the state of the retrieve
     */

    retrieve: function(key, callback, scope) {
      var def = new Deferred();

      scope = scope || this;
      this._store.get(key, function(obj) {
        if(obj === null) {
          if (callback) callback.call(scope, null);
          def.reject();
        }
        else {
          obj.exp = obj.exp < 0 ? null : obj.exp;
          if (callback) callback.call(scope, obj.value, obj.exp);
          def.resolve(obj.value, obj.exp);
        }
      });
      return def;
    },

    /**
     * Recover the last stored session.
     *
     * @private
     */
    _recover: function() {
      var now = + (new Date());
      var self = this;

      this._store.each(function(kv){
        try {
          if(kv.exp >= 0 && kv.exp <= now) {
            self._store.remove(kv.key);
            return;
          }
          self._setExpTimout(kv,kv.exp - now);

          if(typeof kv.rep == 'undefined' || kv.exp <= now) {
            self._republish(kv);
            kv.rep =  now + self._repTime;
            self._store.save(kv);
          }

          self._setRepTimout(kv, kv.rep - now);

        } catch(e) {
          self._store.remove(kv.key);
        }
      });
    },

    /**
     * Reset a timeout for republish of the given Key/Value
     *
     * @private
     * @param {[type]} kv      Key/Value
     * @param {[type]} timeout the timeout
     */
    _setRepTimout: function(kv, timeout) {
      setTimeout(function(kv, self) {
        if(typeof kv == 'undefined') return; //in case of

        //check if it has already expired or if the timer is an old one
        var now = +(new Date());
        var hasExp = (typeof kv.exp == 'undefined' || kv.exp === null || kv.exp <0) ? false : (kv.exp < now);
        var notYet = (kv.rep > now);
        if(hasExp || notYet) return;

        self._republish(kv);
      }, timeout, kv, this);
      return this;
    },

    /**
     * Time between 2 republish processes of a stored value.
     * By default, the value is the TIMEOUT_REPUBLISH global constant.
     *
     * @private
     * @type {Integer}
     */
    _repTime : globals.TIMEOUT_REPUBLISH,

    /**
     * Make a key/value being republished by calling the `republish` method of node instance.
     *
     * Before it checks if key/value is still existing. Reset a new timer.
     *
     * @param  {Object} kv the key/value object to republish
     * @return {Object} this
     */
    _republish: function(kv) {
      var self = this;
      //check before if the key/value still exists
        this._store.exists(kv.key, function(exists) {
          if(exists) {
            //call node's republish method
            self._node.republish(kv.key, kv.value, kv.exp);

            //reset republish date
            var now = +(new Date());
            kv.rep = now + this._repTime;

            //reset a timer
            self._setRepTimout(kv, self._repTime);

            //sore it
            self._store.save(kv);

          }
        });
      return this;
    },

    /**
     * Reset a timeout for expiration of the given Key/Value.
     * If the Key/Value has a negative expiration date (infinite), nothing is done.
     *
     * @private
     * @param {[type]} kv      Key/Value
     * @param {[type]} timeout the timeout
     * @return this
     */
    _setExpTimout: function(kv, timeout) {
      if(kv.exp >= 0) {
        setTimeout(function(kv, self) {
          if(typeof kv == 'undefined') return; //in case of

          //check if it has already expired (old timer)
          var now = +(new Date());
          var hasExp = (typeof kv.exp == 'undefined' || kv.exp === null || kv.exp <0) ? false : (kv.exp < now);
          if(! hasExp) return;

          self._expire(kv);
        }, timeout, kv, this);
      }
      return this;
    },

    /**
     * Make a key/value expire. Before check if stil exists.
     *
     * @private
     * @param  {Object} kv the key/value to make expire
     * @return {Object} this
     */
    _expire: function(kv) {
      var self = this;
      //check before if the key/value still exists
        this._store.exists(kv.key, function(exists) {
          if(exists) {
            self._store.remove(kv.key);
            self.emit('expire', kv);
          }
        });
      return this;
    }

  });

})('object' === typeof module ? module.exports : (this.KadOH = this.KadOH || {}),
   'undefined' == typeof Lawnchair ? undefined : Lawnchair);<|endoftext|>


<commit_before>var termops = require('../lib/util/termops');
var test = require('tape');

test('termops', function(t) {
    t.test('tokenize', function(q) {
        q.test('tokenizes basic strings', function(r) {
            r.deepEqual(termops.tokenize('foo'), ['foo']);
            r.deepEqual(termops.tokenize('foo bar'), ['foo', 'bar']);
            r.deepEqual(termops.tokenize('foo-bar'), ['foo', 'bar']);
            r.deepEqual(termops.tokenize('69-150'), ['69-150']);
            r.deepEqual(termops.tokenize('4-10'), ['4-10']);
            r.deepEqual(termops.tokenize('5-02A'), ['5-02a']);
            r.deepEqual(termops.tokenize('23-'), ['23']);
            r.deepEqual(termops.tokenize('San José'), ['san', 'jose']);
            r.deepEqual(termops.tokenize('San José'), ['san', 'jose']);
            r.deepEqual(termops.tokenize('Chamonix-Mont-Blanc'), ['chamonix','mont','blanc']);
            r.deepEqual(termops.tokenize('Москва'), ['moskva']);
            r.deepEqual(termops.tokenize('京都市'), ['jing','du','shi']);
            r.end();
        });
        q.test('tokenizes lonlat', function(r) {
            r.deepEqual(termops.tokenize('40,0', true), [40,0]);
            r.deepEqual(termops.tokenize('40.00000,-40.31200', true), [40,-40.312]);
            r.deepEqual(termops.tokenize('-120.9129102983109, 45.312312', true), [-120.9129102983109,45.312312]);
            r.deepEqual(termops.tokenize('14th 15th', true), ['14th','15th']);
            r.end();
        });
        q.test('edge cases - empty string', function(r) {
            r.deepEqual(termops.tokenize(''), []);
            r.end()
        });
        q.end();
    });
    t.test('isIdent - tests if searching by id', function(q) {
        var index = {
            country: "",
            province: "",
            place: "",
            postcode: ""
        };
        q.strictEqual(termops.isIdent(index, 'country.5432'), true);
        q.strictEqual(termops.isIdent(index, 'province.123'), true);
        q.strictEqual(termops.isIdent(index, 'postcode.546'), true);
        q.strictEqual(termops.isIdent(index, 'place.455233'), true);
        q.strictEqual(termops.isIdent(index, 'gotham.43213'), false);
        q.strictEqual(termops.isIdent(index, 'country.a445'), false);
        q.strictEqual(termops.isIdent(index, 'place.32f424'), false);
        q.strictEqual(termops.isIdent(index, 'country.424k'), false);
        q.end();
    });
    t.test('tokenMap - maps query tokens', function(q) {
        q.deepEqual([
            'nw',
            'broad',
            'st'
        ], termops.tokenMap({
            'street': 'st',
            'northwest': 'nw'
        }, [
            'northwest',
            'broad',
            'street'
        ]));
        q.end();
    });
    t.test('tokenizeMapping', function(q) {
        q.deepEqual({}, termops.tokenizeMapping({}));
        q.deepEqual({
            'street': 'st'
        }, termops.tokenizeMapping({
            'Street': 'St'
        }));
        q.throws(function() {
            q.deepEqual({
                'north west': 'nw'
            }, termops.tokenizeMapping({
                'North West': 'NW'
            }));
        }, /Invalid mapping token North West/);
        q.end();
    });
    t.test('terms - tokenizes and hashes values', function(q) {
        q.deepEqual(termops.terms(['foo','bar']), [2851307216,1991736592]);
        q.end();
    });
    t.test('termsMap - tokenizes and hashes values', function(q) {
        q.deepEqual(termops.termsMap(['foo','bar']), {
            2851307216: 'foo',
            1991736592: 'bar'
        });
        q.end();
    });
    t.test('degens', function(q) {
        var degens = termops.degens('foobarbaz');
        q.deepEqual(degens, [
            1617781328, 1617781328,
            4112850176, 1617781329,
            2921073328, 1617781330,
            3214735712, 1617781331,
            967483776, 1617781332,
            1062237920, 1617781333,
            2851307216, 1617781334
        ]);
        for (var i = 0; i < degens.length/2; i = i + 2) {
            // Encodes ID for 'foobarbaz'.
            q.equal(degens[i+1] >>> 4 << 4 >>> 0, termops.terms(['foobarbaz'])[0]);
            // Encodes degen distance (max: 15) from foobarbaz.
            q.ok(degens[i+1] % 16 <= 15);
        }
        q.end();
    });
    t.test('phrase - generates a name id', function(q) {
        q.deepEqual(termops.phrase(['foo'], 'foo'), 2851307223);
        q.deepEqual(termops.phrase(['foo','street'], 'foo'), 2851505742);
        q.deepEqual(termops.phrase(['foo','lane'], 'foo'), 2851502143);
        // Clusters phrase IDs based on initial term.
        q.deepEqual(termops.phrase(['foo'], 'foo') >>> 24, 169);
        q.deepEqual(termops.phrase(['foo','street'], 'foo') >>> 24, 169);
        q.deepEqual(termops.phrase(['foo','lane'], 'foo') >>> 24, 169);
        q.end();
    });

    t.test('address', function(q) {
        q.deepEqual(termops.address('500 baker st'), '500', 'full address');
        q.deepEqual(termops.address('baker st'), null, 'no housenum');
        q.deepEqual(termops.address('500'), null, 'only number');
        q.deepEqual(termops.address('500b baker st'), '500b', 'alphanumeric');
        q.deepEqual(termops.address('15th st'), null, 'numbered st');
        q.deepEqual(termops.address('15 st francis drive'), '15', 'ambiguous abbr');
        q.end();
    });

    t.end();
});
<commit_msg>lowercasify<commit_after>var termops = require('../lib/util/termops');
var test = require('tape');

test('termops', function(t) {
    t.test('tokenize', function(q) {
        q.test('tokenizes basic strings', function(r) {
            r.deepEqual(termops.tokenize('foo'), ['foo']);
            r.deepEqual(termops.tokenize('foo bar'), ['foo', 'bar']);
            r.deepEqual(termops.tokenize('foo-bar'), ['foo', 'bar']);
            r.deepEqual(termops.tokenize('69-150'), ['69-150']);
            r.deepEqual(termops.tokenize('4-10'), ['4-10']);
            r.deepEqual(termops.tokenize('5-02a'), ['5-02a']);
            r.deepEqual(termops.tokenize('23-'), ['23']);
            r.deepEqual(termops.tokenize('San José'), ['san', 'jose']);
            r.deepEqual(termops.tokenize('San José'), ['san', 'jose']);
            r.deepEqual(termops.tokenize('Chamonix-Mont-Blanc'), ['chamonix','mont','blanc']);
            r.deepEqual(termops.tokenize('Москва'), ['moskva']);
            r.deepEqual(termops.tokenize('京都市'), ['jing','du','shi']);
            r.end();
        });
        q.test('tokenizes lonlat', function(r) {
            r.deepEqual(termops.tokenize('40,0', true), [40,0]);
            r.deepEqual(termops.tokenize('40.00000,-40.31200', true), [40,-40.312]);
            r.deepEqual(termops.tokenize('-120.9129102983109, 45.312312', true), [-120.9129102983109,45.312312]);
            r.deepEqual(termops.tokenize('14th 15th', true), ['14th','15th']);
            r.end();
        });
        q.test('edge cases - empty string', function(r) {
            r.deepEqual(termops.tokenize(''), []);
            r.end()
        });
        q.end();
    });
    t.test('isIdent - tests if searching by id', function(q) {
        var index = {
            country: "",
            province: "",
            place: "",
            postcode: ""
        };
        q.strictEqual(termops.isIdent(index, 'country.5432'), true);
        q.strictEqual(termops.isIdent(index, 'province.123'), true);
        q.strictEqual(termops.isIdent(index, 'postcode.546'), true);
        q.strictEqual(termops.isIdent(index, 'place.455233'), true);
        q.strictEqual(termops.isIdent(index, 'gotham.43213'), false);
        q.strictEqual(termops.isIdent(index, 'country.a445'), false);
        q.strictEqual(termops.isIdent(index, 'place.32f424'), false);
        q.strictEqual(termops.isIdent(index, 'country.424k'), false);
        q.end();
    });
    t.test('tokenMap - maps query tokens', function(q) {
        q.deepEqual([
            'nw',
            'broad',
            'st'
        ], termops.tokenMap({
            'street': 'st',
            'northwest': 'nw'
        }, [
            'northwest',
            'broad',
            'street'
        ]));
        q.end();
    });
    t.test('tokenizeMapping', function(q) {
        q.deepEqual({}, termops.tokenizeMapping({}));
        q.deepEqual({
            'street': 'st'
        }, termops.tokenizeMapping({
            'Street': 'St'
        }));
        q.throws(function() {
            q.deepEqual({
                'north west': 'nw'
            }, termops.tokenizeMapping({
                'North West': 'NW'
            }));
        }, /Invalid mapping token North West/);
        q.end();
    });
    t.test('terms - tokenizes and hashes values', function(q) {
        q.deepEqual(termops.terms(['foo','bar']), [2851307216,1991736592]);
        q.end();
    });
    t.test('termsMap - tokenizes and hashes values', function(q) {
        q.deepEqual(termops.termsMap(['foo','bar']), {
            2851307216: 'foo',
            1991736592: 'bar'
        });
        q.end();
    });
    t.test('degens', function(q) {
        var degens = termops.degens('foobarbaz');
        q.deepEqual(degens, [
            1617781328, 1617781328,
            4112850176, 1617781329,
            2921073328, 1617781330,
            3214735712, 1617781331,
            967483776, 1617781332,
            1062237920, 1617781333,
            2851307216, 1617781334
        ]);
        for (var i = 0; i < degens.length/2; i = i + 2) {
            // Encodes ID for 'foobarbaz'.
            q.equal(degens[i+1] >>> 4 << 4 >>> 0, termops.terms(['foobarbaz'])[0]);
            // Encodes degen distance (max: 15) from foobarbaz.
            q.ok(degens[i+1] % 16 <= 15);
        }
        q.end();
    });
    t.test('phrase - generates a name id', function(q) {
        q.deepEqual(termops.phrase(['foo'], 'foo'), 2851307223);
        q.deepEqual(termops.phrase(['foo','street'], 'foo'), 2851505742);
        q.deepEqual(termops.phrase(['foo','lane'], 'foo'), 2851502143);
        // Clusters phrase IDs based on initial term.
        q.deepEqual(termops.phrase(['foo'], 'foo') >>> 24, 169);
        q.deepEqual(termops.phrase(['foo','street'], 'foo') >>> 24, 169);
        q.deepEqual(termops.phrase(['foo','lane'], 'foo') >>> 24, 169);
        q.end();
    });

    t.test('address', function(q) {
        q.deepEqual(termops.address('500 baker st'), '500', 'full address');
        q.deepEqual(termops.address('baker st'), null, 'no housenum');
        q.deepEqual(termops.address('500'), null, 'only number');
        q.deepEqual(termops.address('500b baker st'), '500b', 'alphanumeric');
        q.deepEqual(termops.address('15th st'), null, 'numbered st');
        q.deepEqual(termops.address('15 st francis drive'), '15', 'ambiguous abbr');
        q.end();
    });

    t.end();
});
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import firebase, { reference, signIn } from '../firebase';
import { pick, map, extend } from 'lodash';
import SubmitMessage from './submit-message.js';
import ClearInput from './clear-input.js';
import LogInButton from './login-button.js';
import LogOutButton from './logout-button.js';
import SortUp from './sort-up.js';
import SortDown from './sort-down.js';
import moment from 'moment';

export default class Application extends Component {
  constructor() {
    super();
    this.state = {
      messages: [],
      newMessage: '',
      user: '',
      submitButtonDisabled: true,
      clearButtonDisabled: true
    };

  } //end of constructor

  componentDidMount(){

  } //end of componentDidMount

  clearInputField(){
    document.getElementById('message-entry-field').value = '';
    this.disableButtons();
    this.setState({newMessage: ''});
  }

  detectFieldContent(e){
    if (e.target.value !== '') {
      this.enableButtons();
    }
    else {
      this.disableButtons();
    }
  }

  disableButtons(){
    this.setState({submitButtonDisabled: true});
    this.setState({clearButtonDisabled: true});
  }

  enableButtons(){
    this.setState({submitButtonDisabled: false});
    this.setState({clearButtonDisabled: false});
  }

  handleInputChange(e){
    this.setState({newMessage: e.target.value});
    let submitButton = document.querySelector('.submit-message-button');
    let clearButton = document.querySelector('.clear-message-button');
    if (this.state.newMessage !== '') {
      submitButton.removeAttribute('disabled');
      clearButton.removeAttribute('disabled');
    }

  } //end of handleInputChange

  initFirebase(){ //needs to be called on page load
    this.auth = firebase.auth();
    this.database = firebase.database();
    this.auth.onAuthStateChanged(this.onAuthStateChanged.bind(this));
  } // end of initFirebase

  loadMessages(){
    let that = this;
    reference.limitToLast(25).on('value', function (snapshot) {
      var messagesReturned = that.returnArray(snapshot.val());
      that.setState({messages: messagesReturned});
    }); //end of snapshot function
  } //end of loadMessages

  onAuthStateChanged(user){
    if (user) {
      let profilePicUrl = user.photoURL;
      let userName = user.displayName;
      let userNameField = document.getElementById('user-name');
      let userPicField = document.querySelector('.user-pic');
      let logInButton = document.querySelector('.login-button');
      let logOutButton = document.querySelector('.logout-button');
      userNameField.textContent = userName;
      userPicField.setAttribute('src', profilePicUrl);
      userNameField.removeAttribute('hidden');
      userPicField.removeAttribute('hidden');
      logOutButton.removeAttribute('hidden');
      logInButton.setAttribute('hidden', 'true');
      // this.loadMessages();
    } //end of if user is signed in
    else {
      let userNameField = document.getElementById('user-name');
      let userPicField = document.querySelector('.user-pic');
      let signOutButton = document.querySelector('.logout-button');
      userNameField.setAttribute('hidden', 'true');
      userPicField.setAttribute('hidden', 'true');
      signOutButton.setAttribute('hidden', 'true');
      //show the log in button of needed

    } //end of else user is signed out
  } //end of onAuthStateChanged

  isUserSignedIn(){
    if (this.auth.currentUser) {
    return true;
    }
  } //end of isUserSignedIn

  returnArray(snapshots){
    let array = [];
    if (snapshots) {
      var fullArray = Object.keys(snapshots).map((each)=>{
        var singleMessage = snapshots[each];
        singleMessage['each'] = each;
        array.push(singleMessage);
      });
    }
    return array;
  } //end of returnArray

  saveMessage(){
    // event.preventDefault();
    // let that = this;
    if (this.state.newMessage !== '' && this.isUserSignedIn()) {
      //user is signed in
      let currentUser = this.auth.currentUser;
      let body = this.state.newMessage;
      this.state.messages.push(body);
      reference.push({
        user: currentUser.displayName,
        body: body,
        photo: currentUser.photoURL,
        time: moment().toString(),
        id: Date.now()
      });
      this.setState({newMessage: ''});
      this.disableButtons();
      this.loadMessages();
    } //end of if statement
  } //end of saveMessage

  signIn(){
    let provider = new firebase.auth.GoogleAuthProvider();
    this.auth.signInWithPopup(provider);
  } //end of signIn

  signOut(){
    this.auth.signOut();
  }

  sortDown(){ //most recent at bottom
    this.loadMessages();
    this.sortMostRecentAtBottom();
  } //sortUp

  sortMostRecentAtBottom(){
    this.state.messages.sort((a, b)=>{
      return a.id - b.id;
    });
  }

  sortUp(){ //most recent at top
    this.loadMessages();
    let array = this.state.messages;
    let reversed = array.reverse();
    this.setState({messages: reversed});
  }

  render(){
    return (

        <LogInButton handleClick={()=>this.signIn()}/>
        <LogOutButton handleClick={()=>this.signOut()}/>
        <input id="message-entry-field" type="text" placeholder="Message" onChange={this.handleInputChange.bind(this)} value={this.state.newMessage} onKeyUp={this.detectFieldContent.bind(this)} onBlur={this.detectFieldContent.bind(this)}></input>

        Character Count: {this.state.newMessage.length}

        <SubmitMessage handleClick={()=>this.saveMessage()} isDisabled={this.state.submitButtonDisabled}/>
        <ClearInput handleClick={()=>this.clearInputField()} isDisabled={this.state.clearButtonDisabled}/>
        <ChatMaster user={this.state.user} messages={this.state.messages}/>
        <SortUp handleClick={()=>this.sortUp()}/>
        <SortDown handleClick={()=>this.sortDown()}/>

    )
  }

} //end of Application

class ChatMaster extends React.Component {
  constructor(props) {
    super(props);

  } //end of constructor

  showMessages(messages){ //the card for each message
    return(

On {messages.time}, {messages.user} says:

{messages.body}

    )
  }

  render () {
    return (

{this.props.messages.map(this.showMessages)}

Users Present in the Chat Room:

 //end of main div
    );
  }
} //end of ChatMaster

module.exports = Application;
<commit_msg>submit message button is disabled when character count is greater than 140<commit_after>import React, { Component } from 'react';
import firebase, { reference, signIn } from '../firebase';
import { pick, map, extend } from 'lodash';
import SubmitMessage from './submit-message.js';
import ClearInput from './clear-input.js';
import LogInButton from './login-button.js';
import LogOutButton from './logout-button.js';
import SortUp from './sort-up.js';
import SortDown from './sort-down.js';
import moment from 'moment';

export default class Application extends Component {
  constructor() {
    super();
    this.state = {
      messages: [],
      newMessage: '',
      user: '',
      submitButtonDisabled: true,
      clearButtonDisabled: true
    };

  } //end of constructor

  componentDidMount(){

  } //end of componentDidMount

  clearInputField(){
    document.getElementById('message-entry-field').value = '';
    this.disableButtons();
    this.setState({newMessage: ''});
  }

  detectFieldContent(e){
    if (e.target.value !== '') {
      this.enableButtons();
    }
    else {
      this.disableButtons();
    }
  }

  disableButtons(){
    this.setState({submitButtonDisabled: true});
    this.setState({clearButtonDisabled: true});
  }

  enableButtons(){
    this.setState({submitButtonDisabled: false});
    this.setState({clearButtonDisabled: false});
  }

  handleInputChange(e){
    this.setState({newMessage: e.target.value});
    let submitButton = document.querySelector('.submit-message-button');
    let clearButton = document.querySelector('.clear-message-button');
    if (this.state.newMessage !== '') {
      submitButton.removeAttribute('disabled');
      clearButton.removeAttribute('disabled');
    }

      if (this.state.newMessage.length >= 140) {
      submitButton.setAttribute('disabled', 'true');
    }

  } //end of handleInputChange

  initFirebase(){ //needs to be called on page load
    this.auth = firebase.auth();
    this.database = firebase.database();
    this.auth.onAuthStateChanged(this.onAuthStateChanged.bind(this));
  } // end of initFirebase

  loadMessages(){
    let that = this;
    reference.limitToLast(25).on('value', function (snapshot) {
      var messagesReturned = that.returnArray(snapshot.val());
      that.setState({messages: messagesReturned});
    }); //end of snapshot function
  } //end of loadMessages

  onAuthStateChanged(user){
    if (user) {
      let profilePicUrl = user.photoURL;
      let userName = user.displayName;
      let userNameField = document.getElementById('user-name');
      let userPicField = document.querySelector('.user-pic');
      let logInButton = document.querySelector('.login-button');
      let logOutButton = document.querySelector('.logout-button');
      userNameField.textContent = userName;
      userPicField.setAttribute('src', profilePicUrl);
      userNameField.removeAttribute('hidden');
      userPicField.removeAttribute('hidden');
      logOutButton.removeAttribute('hidden');
      logInButton.setAttribute('hidden', 'true');
      // this.loadMessages();
    } //end of if user is signed in
    else {
      let userNameField = document.getElementById('user-name');
      let userPicField = document.querySelector('.user-pic');
      let signOutButton = document.querySelector('.logout-button');
      userNameField.setAttribute('hidden', 'true');
      userPicField.setAttribute('hidden', 'true');
      signOutButton.setAttribute('hidden', 'true');
      //show the log in button of needed

    } //end of else user is signed out
  } //end of onAuthStateChanged

  isUserSignedIn(){
    if (this.auth.currentUser) {
    return true;
    }
  } //end of isUserSignedIn

  returnArray(snapshots){
    let array = [];
    if (snapshots) {
      var fullArray = Object.keys(snapshots).map((each)=>{
        var singleMessage = snapshots[each];
        singleMessage['each'] = each;
        array.push(singleMessage);
      });
    }
    return array;
  } //end of returnArray

  saveMessage(){
    // event.preventDefault();
    // let that = this;
    if (this.state.newMessage !== '' && this.isUserSignedIn()) {
      //user is signed in
      let currentUser = this.auth.currentUser;
      let body = this.state.newMessage;
      this.state.messages.push(body);
      reference.push({
        user: currentUser.displayName,
        body: body,
        photo: currentUser.photoURL,
        time: moment().toString(),
        id: Date.now()
      });
      this.setState({newMessage: ''});
      this.disableButtons();
      this.loadMessages();
    } //end of if statement
  } //end of saveMessage

  signIn(){
    let provider = new firebase.auth.GoogleAuthProvider();
    this.auth.signInWithPopup(provider);
  } //end of signIn

  signOut(){
    this.auth.signOut();
  }

  sortDown(){ //most recent at bottom
    this.loadMessages();
    this.sortMostRecentAtBottom();
  } //sortUp

  sortMostRecentAtBottom(){
    this.state.messages.sort((a, b)=>{
      return a.id - b.id;
    });
  }

  sortUp(){ //most recent at top
    this.loadMessages();
    let array = this.state.messages;
    let reversed = array.reverse();
    this.setState({messages: reversed});
  }

  render(){
    return (

        <LogInButton handleClick={()=>this.signIn()}/>
        <LogOutButton handleClick={()=>this.signOut()}/>
        <input id="message-entry-field" type="text" placeholder="Message" onChange={this.handleInputChange.bind(this)} value={this.state.newMessage} onKeyPress={this.detectFieldContent.bind(this)} onBlur={this.detectFieldContent.bind(this)}></input>

        Character Count: {this.state.newMessage.length}

        <SubmitMessage handleClick={()=>this.saveMessage()} isDisabled={this.state.submitButtonDisabled}/>
        <ClearInput handleClick={()=>this.clearInputField()} isDisabled={this.state.clearButtonDisabled}/>
        <ChatMaster user={this.state.user} messages={this.state.messages}/>
        <SortUp handleClick={()=>this.sortUp()}/>
        <SortDown handleClick={()=>this.sortDown()}/>

    )
  }

} //end of Application

class ChatMaster extends React.Component {
  constructor(props) {
    super(props);

  } //end of constructor

  showMessages(messages){ //the card for each message
    return(

On {messages.time}, {messages.user} says:

{messages.body}

    )
  }

  render () {
    return (

{this.props.messages.map(this.showMessages)}

Users Present in the Chat Room:

 //end of main div
    );
  }
} //end of ChatMaster

module.exports = Application;
<|endoftext|>


<commit_before>'user strict';

var EventEmitter = require('events').EventEmitter;
var Service = require('../service');

module.exports.testService = function(test) {
  test.expect(2);
  var service = new Service({tcpPort: 11137, udpPort: 11137});
  service.on('error', function(error) {
    console.log(error);
    throw(error);
  });
  test.ok(service instanceof Service);
  test.ok(service instanceof EventEmitter);
  service.start(function() {
    service.stop(function() {
      test.done();
    });
  });
};

module.exports.testRegistrationConflict = function(test) {
  test.expect(6);

  var name = 'foobar.example.com';
  var suffix = 0x20;

  // we are going to mock send and receive, so disable network features
  var service = new Service({ tcpDisable: true, udpDisable: true });

  var record = {
    name: name,
    suffix: suffix,
    type: 'nb',
    nb: {
      entries: [{ address: '127.0.0.1', type: 'broadcast', group: false }]
    }
  };

  service._localNames.update(record);

  var request = {
    transactionId: 12345,
    op: 'registration',
    recursionDesired: true,
    questions: [
      { name: name, suffix: suffix, type: 'nb', group: false }
    ],
    additionalRecords: [
      { name: name, suffix: suffix, type: 'nb', ttl: 3600,
        nb: { entries: [{ address: '1.1.1.1', type: 'broadcast', group: false }]}}
    ]
  };

  service._onNetbiosMsg(request, function(msg) {
    test.ok(msg.response);
    test.equal(msg.op, 'registration');
    test.equal(msg.error, 'active');
    test.equal(msg.answerRecords.length, 1);
    test.equal(msg.answerRecords[0].name, name);
    test.equal(msg.answerRecords[0].suffix, suffix);
    test.done();
  });
};

module.exports.testRegistrationNoConflict = function(test) {
  test.expect(1);

  var name = 'foobar.example.com';
  var suffix = 0x20;

  // we are going to mock send and receive, so disable network features
  var service = new Service({ tcpDisable: true, udpDisable: true });

  var request = {
    transactionId: 12345,
    op: 'registration',
    recursionDesired: true,
    questions: [
      { name: name, suffix: suffix, type: 'nb', group: false }
    ],
    additionalRecords: [
      { name: name, suffix: suffix, type: 'nb', ttl: 3600,
        nb: { entries: [{ address: '1.1.1.1', type: 'broadcast', group: false }]}}
    ]
  };

  var gotMessage = false;
  service._onNetbiosMsg(request, function(msg) {
    gotMessage = true;
  });

  process.nextTick(function() {
    test.ok(!gotMessage);
    test.done();
  });
};
<commit_msg>Add test cases for the query handler.<commit_after>'user strict';

var EventEmitter = require('events').EventEmitter;
var Service = require('../service');

module.exports.testService = function(test) {
  test.expect(2);
  var service = new Service({tcpPort: 11137, udpPort: 11137});
  service.on('error', function(error) {
    console.log(error);
    throw(error);
  });
  test.ok(service instanceof Service);
  test.ok(service instanceof EventEmitter);
  service.start(function() {
    service.stop(function() {
      test.done();
    });
  });
};

module.exports.testRegistrationConflict = function(test) {
  test.expect(7);

  var name = 'foobar.example.com';
  var suffix = 0x20;

  // we are going to mock send and receive, so disable network features
  var service = new Service({ tcpDisable: true, udpDisable: true });

  addToCache(service._localNames, name, suffix, false);

  var request = {
    transactionId: 12345,
    op: 'registration',
    recursionDesired: true,
    questions: [
      { name: name, suffix: suffix, type: 'nb', group: false }
    ],
    additionalRecords: [
      { name: name, suffix: suffix, type: 'nb', ttl: 3600,
        nb: { entries: [{ address: '1.1.1.1', type: 'broadcast', group: false }]}}
    ]
  };

  service._onNetbiosMsg(request, function(msg) {
    test.ok(msg.response);
    test.equal(msg.transactionId, request.transactionId);
    test.equal(msg.op, 'registration');
    test.equal(msg.error, 'active');
    test.equal(msg.answerRecords.length, 1);
    test.equal(msg.answerRecords[0].name, name);
    test.equal(msg.answerRecords[0].suffix, suffix);
    test.done();
  });
};

module.exports.testRegistrationNoConflict = function(test) {
  test.expect(1);

  var name = 'foobar.example.com';
  var suffix = 0x20;

  // we are going to mock send and receive, so disable network features
  var service = new Service({ tcpDisable: true, udpDisable: true });

  var request = {
    transactionId: 12345,
    op: 'registration',
    recursionDesired: true,
    questions: [
      { name: name, suffix: suffix, type: 'nb', group: false }
    ],
    additionalRecords: [
      { name: name, suffix: suffix, type: 'nb', ttl: 3600,
        nb: { entries: [{ address: '1.1.1.1', type: 'broadcast', group: false }]}}
    ]
  };

  var gotMessage = false;
  service._onNetbiosMsg(request, function(msg) {
    gotMessage = true;
  });

  process.nextTick(function() {
    test.ok(!gotMessage);
    test.done();
  });
};

module.exports.testQueryNb = function(test) {
  test.expect(8);

  var service = new Service({ tcpDisable: true, udpDisable: true });

  var name = 'foobar.example.com';
  var suffix = 0x20;
  var group = false;

  addToCache(service._localNames, name, suffix, group);

  var request = {
    transactionId: 67890,
    op: 'query',
    recursionDesired: true,
    questions: [
      { name: name, suffix: suffix, type: 'nb', group: group }
    ]
  };

  service._onNetbiosMsg(request, function(msg) {
    test.ok(msg.response);
    test.equal(msg.transactionId, request.transactionId);
    test.equal(msg.op, 'query');
    test.ok(!msg.error);
    test.equal(msg.answerRecords.length, 1);
    test.equal(msg.answerRecords[0].name, name);
    test.equal(msg.answerRecords[0].suffix, suffix);
    test.equal(msg.answerRecords[0].type, 'nb');
    test.done();
  });
};

module.exports.testQueryNbMissing = function(test) {
  test.expect(1);

  var service = new Service({ tcpDisable: true, udpDisable: true });

  var name = 'foobar.example.com';
  var suffix = 0x20;
  var group = false;

  var request = {
    transactionId: 67890,
    op: 'query',
    recursionDesired: true,
    questions: [
      { name: name, suffix: suffix, type: 'nb', group: group }
    ]
  };

  var gotMsg = false;
  service._onNetbiosMsg(request, function(msg) {
    gotMsg = true;
  });

  process.nextTick(function() {
    test.ok(!gotMsg);
    test.done();
  });
};

module.exports.testQueryNbstat = function(test) {
  test.expect(11);

  var service = new Service({ tcpDisable: true, udpDisable: true });

  var names = [
    'foobar.example.com',
    'snafu.example.com',
    'foobar',
    'snafu'
  ];
  var suffix = 0x20;
  var group = false;

  names.forEach(function(name) {
    addToCache(service._localNames, name, suffix, group);
  });

  var request = {
    transactionId: 89012,
    op: 'query',
    recursionDesired: true,
    questions: [
      { name: names[0], suffix: suffix, type: 'nbstat', group: group }
    ]
  };

  service._onNetbiosMsg(request, function(msg) {
    test.ok(msg.response);
    test.equal(msg.transactionId, request.transactionId);
    test.equal(msg.op, 'query');
    test.ok(!msg.error);
    test.equal(msg.answerRecords.length, 1);
    var answer = msg.answerRecords[0];
    test.equal(answer.name, names[0]);
    test.equal(answer.suffix, suffix);
    test.equal(answer.type, 'nbstat');

    // we should only get the first two names because the results are filtered
    // by the requested scope ID
    test.equal(answer.nbstat.nodes.length, 2);
    var foundNames = {};
    answer.nbstat.nodes.forEach(function(node) {
      foundNames[node.name] = true;
    });
    test.ok(foundNames[names[0]]);
    test.ok(foundNames[names[1]]);

    test.done();
  });
};

function addToCache(cache, name, suffix, group) {
  var record = {
    name: name,
    suffix: suffix,
    type: 'nb',
    nb: {
      entries: [{ address: '127.0.0.1', type: 'broadcast', group: group }]
    }
  };

  cache.update(record);
}
<|endoftext|>


<commit_before>'use strict';

import {RedocComponent, BaseComponent} from '../base';
import SchemaManager from '../../utils/SchemaManager';

import ApiInfo from '../ApiInfo/api-info';
import ApiLogo from '../ApiLogo/api-logo';
import MethodsList from '../MethodsList/methods-list';
import SideMenu from '../SideMenu/side-menu';
import StickySidebar from '../../common/components/StickySidebar/sticky-sidebar';
import OptionsManager from '../../options';
import {redocEvents} from '../../events';

import {ChangeDetectionStrategy} from 'angular2/core';
import {ElementRef} from 'angular2/core';
import {BrowserDomAdapter, bootstrap} from 'angular2/platform/browser';
import detectScollParent from 'scrollparent';

import {isFunction} from 'angular2/src/facade/lang';

let optionNames = new Set(['scrollYOffset']);

@RedocComponent({
  selector: 'redoc',
  providers: [SchemaManager, BrowserDomAdapter, OptionsManager],
  templateUrl: './lib/components/Redoc/redoc.html',
  styleUrls: ['./lib/components/Redoc/redoc.css'],
  directives: [ApiInfo, ApiLogo, MethodsList, SideMenu, StickySidebar],
  changeDetection: ChangeDetectionStrategy.Default
})
export default class Redoc extends BaseComponent {
  constructor(schemaMgr, optionsMgr, elementRef, dom) {
    super(schemaMgr);
    this.element = elementRef.nativeElement;

    this.dom = dom;
    let el = this.element;

    //parse options (top level component doesn't support inputs)
    this.scrollParent = detectScollParent(el);
    this.parseOptions();
    this.options = Object.assign({}, optionsMgr.options, this.options);
    this.normalizeOptions();
  }

  parseOptions() {
    let attributesMap = this.dom.attributeMap(this.element);
    this.options = {};
    Array.from(attributesMap.keys())
      //camelCasify
      .map(k => ({
        attrName: k,
        name: k.replace(/-(.)/g,  (m, $1) => $1.toUpperCase())
        })
      )
      .filter(option => optionNames.has(option.name))
      .forEach(option => {
        this.options[option.name] = attributesMap.get(option.attrName);
      });
  }

  normalizeOptions() {
    // modify scrollYOffset to always be a function
    if (!isFunction(this.options.scrollYOffset)) {
      if (isFinite(this.options.scrollYOffset)) {
        // if number specified create function that returns this value
        let numberOffset = parseFloat(this.options.scrollYOffset);
        this.options.scrollYOffset = () => numberOffset;
      } else {
        // if selector or node function that returns bottom offset of this node
        let el = this.options.scrollYOffset;
        if (!(el instanceof Node)) {
          el = this.dom.query(el);
        }
        if (!el) {
          this.options.scrollYOffset = () => 0;
        } else {
          this.options.scrollYOffset = () => el.offsetTop + el.offsetHeight;
        }
      }
    }
  }

  static init(schemaUrl, options) {
    if (Redoc.appRef) {
      Redoc.dispose();
    }
    return SchemaManager.instance().load(schemaUrl)
    .then(() => {
      (new OptionsManager()).options = options;
      return bootstrap(Redoc);
    })
    .then(
      (appRef) => {
        Redoc.appRef = appRef;
        redocEvents.bootstrapped.next();
        console.log('ReDoc bootstrapped!');
      },
      error => {
        console.log(error);
        throw error;
      }
    );
  }

  static autoInit() {
    const specUrlAttributeName = 'spec-url';
    let dom = new BrowserDomAdapter();
    let redocEl = dom.query('redoc');
    if (!redocEl) return;
    if (dom.hasAttribute(redocEl, specUrlAttributeName)) {
      let url = dom.getAttribute(redocEl, specUrlAttributeName);
      Redoc.init(url);
    }
  }

  static dispose() {
    let dom = new BrowserDomAdapter();
    let el = dom.query('redoc');
    let parent;
    let nextSibling;
    if (el) {
      parent = el.parentElement;
      nextSibling = el.nextElementSibling;
    }

    if (Redoc.appRef) {
      Redoc.appRef.dispose();
      Redoc.appRef = null;

      // Redoc dispose removes host element, so need to restore it
      el = dom.createElement('redoc');
      el.innerText = 'Loading...';
      parent && parent.insertBefore(el, nextSibling);
    }
  }
}
Redoc.parameters = Redoc.parameters.concat([[OptionsManager], [ElementRef], [BrowserDomAdapter]]);

// TODO
// this doesn't work in side-menu.js because of some circular references issue
SideMenu.parameters = SideMenu.parameters.concat([[Redoc]]);
<commit_msg>Preserve redoc element params after dispose<commit_after>'use strict';

import {RedocComponent, BaseComponent} from '../base';
import SchemaManager from '../../utils/SchemaManager';

import ApiInfo from '../ApiInfo/api-info';
import ApiLogo from '../ApiLogo/api-logo';
import MethodsList from '../MethodsList/methods-list';
import SideMenu from '../SideMenu/side-menu';
import StickySidebar from '../../common/components/StickySidebar/sticky-sidebar';
import OptionsManager from '../../options';
import {redocEvents} from '../../events';

import {ChangeDetectionStrategy} from 'angular2/core';
import {ElementRef} from 'angular2/core';
import {BrowserDomAdapter, bootstrap} from 'angular2/platform/browser';
import detectScollParent from 'scrollparent';

import {isFunction} from 'angular2/src/facade/lang';

let optionNames = new Set(['scrollYOffset']);

@RedocComponent({
  selector: 'redoc',
  providers: [SchemaManager, BrowserDomAdapter, OptionsManager],
  templateUrl: './lib/components/Redoc/redoc.html',
  styleUrls: ['./lib/components/Redoc/redoc.css'],
  directives: [ApiInfo, ApiLogo, MethodsList, SideMenu, StickySidebar],
  changeDetection: ChangeDetectionStrategy.Default
})
export default class Redoc extends BaseComponent {
  constructor(schemaMgr, optionsMgr, elementRef, dom) {
    super(schemaMgr);
    this.element = elementRef.nativeElement;

    this.dom = dom;
    let el = this.element;

    //parse options (top level component doesn't support inputs)
    this.scrollParent = detectScollParent(el);
    this.parseOptions();
    this.options = Object.assign({}, optionsMgr.options, this.options);
    this.normalizeOptions();
  }

  parseOptions() {
    let attributesMap = this.dom.attributeMap(this.element);
    this.options = {};
    Array.from(attributesMap.keys())
      //camelCasify
      .map(k => ({
        attrName: k,
        name: k.replace(/-(.)/g,  (m, $1) => $1.toUpperCase())
        })
      )
      .filter(option => optionNames.has(option.name))
      .forEach(option => {
        this.options[option.name] = attributesMap.get(option.attrName);
      });
  }

  normalizeOptions() {
    // modify scrollYOffset to always be a function
    if (!isFunction(this.options.scrollYOffset)) {
      if (isFinite(this.options.scrollYOffset)) {
        // if number specified create function that returns this value
        let numberOffset = parseFloat(this.options.scrollYOffset);
        this.options.scrollYOffset = () => numberOffset;
      } else {
        // if selector or node function that returns bottom offset of this node
        let el = this.options.scrollYOffset;
        if (!(el instanceof Node)) {
          el = this.dom.query(el);
        }
        if (!el) {
          this.options.scrollYOffset = () => 0;
        } else {
          this.options.scrollYOffset = () => el.offsetTop + el.offsetHeight;
        }
      }
    }
  }

  static init(schemaUrl, options) {
    if (Redoc.appRef) {
      Redoc.dispose();
    }
    return SchemaManager.instance().load(schemaUrl)
    .then(() => {
      (new OptionsManager()).options = options;
      return bootstrap(Redoc);
    })
    .then(
      (appRef) => {
        Redoc.appRef = appRef;
        redocEvents.bootstrapped.next();
        console.log('ReDoc bootstrapped!');
      },
      error => {
        console.log(error);
        throw error;
      }
    );
  }

  static autoInit() {
    const specUrlAttributeName = 'spec-url';
    let dom = new BrowserDomAdapter();
    let redocEl = dom.query('redoc');
    if (!redocEl) return;
    if (dom.hasAttribute(redocEl, specUrlAttributeName)) {
      let url = dom.getAttribute(redocEl, specUrlAttributeName);
      Redoc.init(url);
    }
  }

  static dispose() {
    let dom = new BrowserDomAdapter();
    let el = dom.query('redoc');
    let elClone;
    let parent;
    let nextSibling;
    if (el) {
      parent = el.parentElement;
      nextSibling = el.nextElementSibling;
    }

    elClone = el.cloneNode(false);

    if (Redoc.appRef) {
      Redoc.appRef.dispose();
      Redoc.appRef = null;

      // Redoc dispose removes host element, so need to restore it
      elClone.innerHTML = 'Loading...';
      parent && parent.insertBefore(elClone, nextSibling);
    }
  }
}
Redoc.parameters = Redoc.parameters.concat([[OptionsManager], [ElementRef], [BrowserDomAdapter]]);

// TODO
// this doesn't work in side-menu.js because of some circular references issue
SideMenu.parameters = SideMenu.parameters.concat([[Redoc]]);
<|endoftext|>


<commit_before>var numeral = require("numeral");
let id_regex = /\b\d+\.\d+\.(\d+)\b/;

import {object_type} from "chain/chain_types";

var Utils = {
    get_object_id: (obj_id) => {
        let id_regex_res = id_regex.exec(obj_id);
        return id_regex_res ? Number.parseInt(id_regex_res[1]) : 0;
    },

    is_object_id: (obj_id) => {
        if( 'string' != typeof obj_id ) return false
        let match = id_regex.exec(obj_id);
        return (match !== null && obj_id.split(".").length === 3);
    },

    get_asset_precision: (precision) => {
        return Math.pow(10, precision);
    },

    get_asset_amount: function(amount, asset) {
        return amount / this.get_asset_precision(asset.precision);
    },

    get_asset_price: function(quoteAmount, quoteAsset, baseAmount, baseAsset) {
        return this.get_asset_amount(quoteAmount, quoteAsset) / this.get_asset_amount(baseAmount, baseAsset);
    },

    round_number: function(number, asset) {
        let precision = this.get_asset_precision(asset.precision);
        return Math.round(number * precision) / precision;
    },

    format_number: (number, decimals, trailing_zeros = true) => {
        let zeros = ".";
        for (var i = 0; i < decimals; i++) {
            zeros += "0";
        }
        let num = numeral(number).format("0,0" + zeros);
        if( num.indexOf('.') > 0 && !trailing_zeros)
           return num.replace(/0+$/,"").replace(/\.$/,"")
        return num
    },

    format_asset: function(amount, asset, noSymbol, trailing_zeros=true) {
        let symbol = asset
        let digits = 0
        if( asset === undefined )
           return undefined
        if( 'symbol' in asset )
        {
            console.log( "asset: ", asset )
            symbol = asset.symbol
            digits = asset.precision
        }
        else
        {
           console.log( "asset: ", asset.toJS() )
           symbol = asset.get('symbol')
           digits = asset.get('precision')
        }
        let precision = this.get_asset_precision(digits);
        console.log( "precision: ", precision )

        return `${this.format_number(amount / precision, digits, trailing_zeros)}${!noSymbol ? " " + symbol : ""}`;
    },

    format_price: function(quoteAmount, quoteAsset, baseAmount, baseAsset, noSymbol,inverted,trailing_zeros=true) {
        let precision = this.get_asset_precision(quoteAsset.precision);
        let basePrecision = this.get_asset_precision(baseAsset.precision);
        if (inverted) {
            if (parseInt(quoteAsset.id.split(".")[2], 10) < parseInt(baseAsset.id.split(".")[2], 10)) {
                return `${this.format_number((quoteAmount / precision) / (baseAmount / basePrecision), Math.max(5, quoteAsset.precision),trailing_zeros)}${!noSymbol ? " " + quoteAsset.symbol + "/" + baseAsset.symbol : ""}`;
            } else {
                return `${this.format_number((baseAmount / basePrecision) / (quoteAmount / precision), Math.max(5, baseAsset.precision),trailing_zeros)}${!noSymbol ? " " + baseAsset.symbol + "/" + quoteAsset.symbol : ""}`;
            }
        } else {
            if (parseInt(quoteAsset.id.split(".")[2], 10) > parseInt(baseAsset.id.split(".")[2], 10)) {
                return `${this.format_number((quoteAmount / precision) / (baseAmount / basePrecision), Math.max(5, quoteAsset.precision),trailing_zeros)}${!noSymbol ? " " + quoteAsset.symbol + "/" + baseAsset.symbol : ""}`;
            } else {
                return `${this.format_number((baseAmount / basePrecision) / (quoteAmount / precision), Math.max(5, baseAsset.precision),trailing_zeros)}${!noSymbol ? " " + baseAsset.symbol + "/" + quoteAsset.symbol : ""}`;
            }
        }
    },

    get_op_type: function(object) {
        let type = parseInt(object.split(".")[1], 10);

        for (let id in object_type) {
            if (object_type[id] === type) {
                return id;
            }
        }
    },

    add_comma: function(value) {
        if (typeof value === "number") {
            value = value.toString();
        }
        value = value.trim()
        value = value.replace( /,/g, "" )
        if( value == "." || value == "" ) {
           return value;
        }
        else if( value.length ) {
            // console.log( "before: ",value )
            let n = Number(value)
            if( isNaN( n ) )
                return
            let parts = value.split('.')
            // console.log( "split: ", parts )
            n = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
            if( parts.length > 1 )
                n += "." + parts[1]
            // console.log( "after: ",transfer.amount )
            return n;
       }
    },

    parse_float_with_comma: function(value) {
        // let value = new_state.transfer.amount
        value = value.replace( /,/g, "" )
        let fvalue = parseFloat(value)
        if( value.length && isNaN(fvalue) && value != "." )
           throw "parse_float_with_comma: must be a number"
         else if( fvalue < 0 )
           return 0;

        return fvalue;
    },

    are_equal_shallow: function(a, b) {
        for(var key in a) {
            if(!(key in b) || a[key] !== b[key]) {
                return false;
            }
        }
        for(var key in b) {
            if(!(key in a) || a[key] !== b[key]) {
                return false;
            }
        }
        return true;
    }
};

module.exports = Utils;
<commit_msg>Convert assets to js if immutable in utils.format_price<commit_after>var numeral = require("numeral");
let id_regex = /\b\d+\.\d+\.(\d+)\b/;

import {object_type} from "chain/chain_types";

var Utils = {
    get_object_id: (obj_id) => {
        let id_regex_res = id_regex.exec(obj_id);
        return id_regex_res ? Number.parseInt(id_regex_res[1]) : 0;
    },

    is_object_id: (obj_id) => {
        if( 'string' != typeof obj_id ) return false
        let match = id_regex.exec(obj_id);
        return (match !== null && obj_id.split(".").length === 3);
    },

    get_asset_precision: (precision) => {
        return Math.pow(10, precision);
    },

    get_asset_amount: function(amount, asset) {
        return amount / this.get_asset_precision(asset.precision);
    },

    get_asset_price: function(quoteAmount, quoteAsset, baseAmount, baseAsset) {
        return this.get_asset_amount(quoteAmount, quoteAsset) / this.get_asset_amount(baseAmount, baseAsset);
    },

    round_number: function(number, asset) {
        let precision = this.get_asset_precision(asset.precision);
        return Math.round(number * precision) / precision;
    },

    format_number: (number, decimals, trailing_zeros = true) => {
        let zeros = ".";
        for (var i = 0; i < decimals; i++) {
            zeros += "0";
        }
        let num = numeral(number).format("0,0" + zeros);
        if( num.indexOf('.') > 0 && !trailing_zeros)
           return num.replace(/0+$/,"").replace(/\.$/,"")
        return num
    },

    format_asset: function(amount, asset, noSymbol, trailing_zeros=true) {
        let symbol;
        let digits = 0
        if( asset === undefined )
           return undefined
        if( 'symbol' in asset )
        {
            console.log( "asset: ", asset )
            symbol = asset.symbol
            digits = asset.precision
        }
        else
        {
           console.log( "asset: ", asset.toJS() )
           symbol = asset.get('symbol')
           digits = asset.get('precision')
        }
        let precision = this.get_asset_precision(digits);
        console.log( "precision: ", precision )

        return `${this.format_number(amount / precision, digits, trailing_zeros)}${!noSymbol ? " " + symbol : ""}`;
    },

    format_price: function(quoteAmount, quoteAsset, baseAmount, baseAsset, noSymbol,inverted,trailing_zeros=true) {
        if (quoteAsset.size) quoteAsset = quoteAsset.toJS();
        if (baseAsset.size) baseAsset = baseAsset.toJS();

        let precision = this.get_asset_precision(quoteAsset.precision);
        let basePrecision = this.get_asset_precision(baseAsset.precision);

        if (inverted) {
            if (parseInt(quoteAsset.id.split(".")[2], 10) < parseInt(baseAsset.id.split(".")[2], 10)) {
                return `${this.format_number((quoteAmount / precision) / (baseAmount / basePrecision), Math.max(5, quoteAsset.precision),trailing_zeros)}${!noSymbol ? " " + quoteAsset.symbol + "/" + baseAsset.symbol : ""}`;
            } else {
                return `${this.format_number((baseAmount / basePrecision) / (quoteAmount / precision), Math.max(5, baseAsset.precision),trailing_zeros)}${!noSymbol ? " " + baseAsset.symbol + "/" + quoteAsset.symbol : ""}`;
            }
        } else {
            if (parseInt(quoteAsset.id.split(".")[2], 10) > parseInt(baseAsset.id.split(".")[2], 10)) {
                return `${this.format_number((quoteAmount / precision) / (baseAmount / basePrecision), Math.max(5, quoteAsset.precision),trailing_zeros)}${!noSymbol ? " " + quoteAsset.symbol + "/" + baseAsset.symbol : ""}`;
            } else {
                return `${this.format_number((baseAmount / basePrecision) / (quoteAmount / precision), Math.max(5, baseAsset.precision),trailing_zeros)}${!noSymbol ? " " + baseAsset.symbol + "/" + quoteAsset.symbol : ""}`;
            }
        }
    },

    get_op_type: function(object) {
        let type = parseInt(object.split(".")[1], 10);

        for (let id in object_type) {
            if (object_type[id] === type) {
                return id;
            }
        }
    },

    add_comma: function(value) {
        if (typeof value === "number") {
            value = value.toString();
        }
        value = value.trim()
        value = value.replace( /,/g, "" )
        if( value == "." || value == "" ) {
           return value;
        }
        else if( value.length ) {
            // console.log( "before: ",value )
            let n = Number(value)
            if( isNaN( n ) )
                return
            let parts = value.split('.')
            // console.log( "split: ", parts )
            n = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
            if( parts.length > 1 )
                n += "." + parts[1]
            // console.log( "after: ",transfer.amount )
            return n;
       }
    },

    parse_float_with_comma: function(value) {
        // let value = new_state.transfer.amount
        value = value.replace( /,/g, "" )
        let fvalue = parseFloat(value)
        if( value.length && isNaN(fvalue) && value != "." )
           throw "parse_float_with_comma: must be a number"
         else if( fvalue < 0 )
           return 0;

        return fvalue;
    },

    are_equal_shallow: function(a, b) {
        for(var key in a) {
            if(!(key in b) || a[key] !== b[key]) {
                return false;
            }
        }
        for(var key in b) {
            if(!(key in a) || a[key] !== b[key]) {
                return false;
            }
        }
        return true;
    }
};

module.exports = Utils;
<|endoftext|>


<commit_before>/*jshint expr: true*/
var expect = require('chai').expect;

var fanci = require('../lib/fanci');
var source = require('../example/source');

describe('Extract full object', function() {
    it('should return the whole objects as it was before', function() {
        var template = {
            '*': true
        };
        expect(fanci.extract(source, template)).to.be.deep.equal(source);
    });
});

describe('Extract empty template', function() {
    it('should return an empty object', function() {
        var template = {};
        expect(fanci.extract(source, template)).to.be.empty;
    });
});

describe('Extract empty source', function() {
    it('should return an empty object', function() {
        var template = {
            'products': {
                '*': true
            }
        };
        expect(fanci.extract({}, template)).to.be.empty;
    });
});

describe('Extract empty source', function() {
    it('should return an empty object', function() {
        var template = {
            'products': {
                '*': true
            }
        };
        expect(fanci.extract({}, template)).to.be.empty;
    });
});

describe('Extract arbitrary keys with *', function() {
    it('should return all objects', function() {
        var template = {
            'products': {
                '*': true
            }
        };
        expect(fanci.extract(source, template)).to.be.deep.equal({
            "products": {
                "1234": {
                    "id": 1234,
                    "internal_id": "X04BEEF",
                    "name": "The Beef",
                    "status": {
                        "available": true
                    },
                    "delivery": {
                        "company": "My Transport",
                        "rate": "business_hour",
                        "time": "daily"
                    }
                },
                "4567": {
                    "id": 4567,
                    "internal_id": "X08CAFE",
                    "name": "El Coffee",
                    "status": {
                        "available": true
                    },
                    "delivery": {
                        "company": "Ayayay",
                        "rate": "weekend",
                        "time": "weekend"
                    }
                },
                "6789": {
                    "id": 6789,
                    "internal_id": "X07DEAD",
                    "name": "Life Product",
                    "status": {
                        "available": false
                    },
                    "delivery": {
                        "company": "My Transport",
                        "rate": "business_hour",
                        "time": "weekend"
                    }
                }
            }
        });
    });
});

describe('Extract only a subset of keys', function() {
    it('should return objects with only those keys', function() {
        var template = {
            'products': {
                '*': {
                    'id': true,
                    'name': true,
                    'status': true
                }
            }
        };
        expect(fanci.extract(source, template)).to.be.deep.equal({
            "products": {
                "1234": {
                    "id": 1234,
                    "name": "The Beef",
                    "status": {
                        "available": true
                    }
                },
                "4567": {
                    "id": 4567,
                    "name": "El Coffee",
                    "status": {
                        "available": true
                    }
                },
                "6789": {
                    "id": 6789,
                    "name": "Life Product",
                    "status": {
                        "available": false
                    }
                }
            }
        });
    });
});

describe('Extract an array of objects', function() {
    it('should return the array of objects', function() {
        var template = {
            'docs': true
        };
        expect(fanci.extract(source, template)).to.be.deep.equal({
            "docs": [
                {
                    "author": "Gandalf",
                    "date": "2014-02-03",
                    "description": "Put some magic in here"
                },
                {
                    "author": "Harry",
                    "date": "2014-02-04",
                    "description": "Rainbow Unicorns!"
                },
                {
                    "author": "Phil",
                    "date": "2014-05-19",
                    "description": "Valuable information"
                },
                {
                    "author": "Odi",
                    "date": "2014-05-22",
                    "description": "Fanci stuff!"
                }
            ]
        });
    });
});

describe('Extract object subset from array', function() {
    it('should return objects with only those keys', function() {
        var template = {
            'docs': {
                '*': {
                    'author': true
                }
            }
        };
        expect(fanci.extract(source, template)).to.be.deep.equal({
            "docs": [
                {
                    "author": "Gandalf"
                },
                {
                    "author": "Harry"
                },
                {
                    "author": "Phil"
                },
                {
                    "author": "Odi"
                }
            ]
        });
    });
});

describe('Extract from array', function() {
    it('should return an array with the extacted objects', function() {
        var template = {
            '*': {
                'author': true
            }
        };
        expect(fanci.extract(source.docs, template)).to.be.deep.equal([
            {
                "author": "Gandalf"
            },
            {
                "author": "Harry"
            },
            {
                "author": "Phil"
            },
            {
                "author": "Odi"
            }
        ]);
    });
});

describe('Extract subset from array', function() {
    it('should return only the specified subset of the array', function() {
        var template = {
            'docs': {
                '0': {
                    'author': true
                },
                '3': {
                    'description': true
                }
            }
        };
        expect(fanci.extract(source, template)).to.be.deep.equal({
            "docs": [
                {
                    "author": "Gandalf"
                },
                {
                    "description": "Fanci stuff!"
                }
            ]
        });
    });
});
<commit_msg>Remove duplicate test case<commit_after>/*jshint expr: true*/
var expect = require('chai').expect;

var fanci = require('../lib/fanci');
var source = require('../example/source');

describe('Extract full object', function() {
    it('should return the whole objects as it was before', function() {
        var template = {
            '*': true
        };
        expect(fanci.extract(source, template)).to.be.deep.equal(source);
    });
});

describe('Extract empty template', function() {
    it('should return an empty object', function() {
        var template = {};
        expect(fanci.extract(source, template)).to.be.empty;
    });
});

describe('Extract empty source', function() {
    it('should return an empty object', function() {
        var template = {
            'products': {
                '*': true
            }
        };
        expect(fanci.extract({}, template)).to.be.empty;
    });
});

describe('Extract arbitrary keys with *', function() {
    it('should return all objects', function() {
        var template = {
            'products': {
                '*': true
            }
        };
        expect(fanci.extract(source, template)).to.be.deep.equal({
            "products": {
                "1234": {
                    "id": 1234,
                    "internal_id": "X04BEEF",
                    "name": "The Beef",
                    "status": {
                        "available": true
                    },
                    "delivery": {
                        "company": "My Transport",
                        "rate": "business_hour",
                        "time": "daily"
                    }
                },
                "4567": {
                    "id": 4567,
                    "internal_id": "X08CAFE",
                    "name": "El Coffee",
                    "status": {
                        "available": true
                    },
                    "delivery": {
                        "company": "Ayayay",
                        "rate": "weekend",
                        "time": "weekend"
                    }
                },
                "6789": {
                    "id": 6789,
                    "internal_id": "X07DEAD",
                    "name": "Life Product",
                    "status": {
                        "available": false
                    },
                    "delivery": {
                        "company": "My Transport",
                        "rate": "business_hour",
                        "time": "weekend"
                    }
                }
            }
        });
    });
});

describe('Extract only a subset of keys', function() {
    it('should return objects with only those keys', function() {
        var template = {
            'products': {
                '*': {
                    'id': true,
                    'name': true,
                    'status': true
                }
            }
        };
        expect(fanci.extract(source, template)).to.be.deep.equal({
            "products": {
                "1234": {
                    "id": 1234,
                    "name": "The Beef",
                    "status": {
                        "available": true
                    }
                },
                "4567": {
                    "id": 4567,
                    "name": "El Coffee",
                    "status": {
                        "available": true
                    }
                },
                "6789": {
                    "id": 6789,
                    "name": "Life Product",
                    "status": {
                        "available": false
                    }
                }
            }
        });
    });
});

describe('Extract an array of objects', function() {
    it('should return the array of objects', function() {
        var template = {
            'docs': true
        };
        expect(fanci.extract(source, template)).to.be.deep.equal({
            "docs": [
                {
                    "author": "Gandalf",
                    "date": "2014-02-03",
                    "description": "Put some magic in here"
                },
                {
                    "author": "Harry",
                    "date": "2014-02-04",
                    "description": "Rainbow Unicorns!"
                },
                {
                    "author": "Phil",
                    "date": "2014-05-19",
                    "description": "Valuable information"
                },
                {
                    "author": "Odi",
                    "date": "2014-05-22",
                    "description": "Fanci stuff!"
                }
            ]
        });
    });
});

describe('Extract object subset from array', function() {
    it('should return objects with only those keys', function() {
        var template = {
            'docs': {
                '*': {
                    'author': true
                }
            }
        };
        expect(fanci.extract(source, template)).to.be.deep.equal({
            "docs": [
                {
                    "author": "Gandalf"
                },
                {
                    "author": "Harry"
                },
                {
                    "author": "Phil"
                },
                {
                    "author": "Odi"
                }
            ]
        });
    });
});

describe('Extract from array', function() {
    it('should return an array with the extacted objects', function() {
        var template = {
            '*': {
                'author': true
            }
        };
        expect(fanci.extract(source.docs, template)).to.be.deep.equal([
            {
                "author": "Gandalf"
            },
            {
                "author": "Harry"
            },
            {
                "author": "Phil"
            },
            {
                "author": "Odi"
            }
        ]);
    });
});

describe('Extract subset from array', function() {
    it('should return only the specified subset of the array', function() {
        var template = {
            'docs': {
                '0': {
                    'author': true
                },
                '3': {
                    'description': true
                }
            }
        };
        expect(fanci.extract(source, template)).to.be.deep.equal({
            "docs": [
                {
                    "author": "Gandalf"
                },
                {
                    "description": "Fanci stuff!"
                }
            ]
        });
    });
});
<|endoftext|>