<commit_before>#!/usr/bin/env node
"use strict";

// increase the libuv threadpool size to 1.5x the number of logical CPUs.
process.env.UV_THREADPOOL_SIZE = process.env.UV_THREADPOOL_SIZE ||
  Math.ceil(Math.max(4, require('os').cpus().length * 1.5));

var path = require("path"),
  debug = require("debug"),
  rabbit = require('rabbit.js'),
  Q = require("q");

debug = debug("tile-squirrel-cacher");

module.exports = function(opts) {
  var tilelive = require("tilelive");

  // load and register tilelive modules
  require("tilelive-modules/loader")(tilelive, opts);

  if (opts.uri) {
    throw "For now you must use a config file in queue mode";
  }

  //Load all sources
  var sources = {};
  var sinks = {};

  if (opts.config) {
    var config = require(path.resolve(opts.config));
    debug("Loading " + Object.keys(config).length + " sources");

    var sourceLoadingPromises = [];
    Object.keys(config).forEach(function(prefix) {
      (function(){
        var key = prefix;
        var deferred = Q.defer();
        sourceLoadingPromises.push(deferred.promise);
        tilelive.load(config[prefix]['source'], function(err, src){
          if(err) {
            console.log("Error loading source " + config[prefix]['source']);
            deferred.reject(err);
          }
          sources[key] = src;
          tilelive.load(config[prefix]['destination'], function(err, dest){
            if(err) {
              console.log("Error loading destination " + config[prefix]['destination']);
              deferred.reject(err);
            } else {
              sinks[key] = dest;
              src.getInfo(function(err, data){
                if(err){
                  deferred.reject(err);
                } else {
                  if(data) {
                    dest.startWriting(function(err){
                      if(err) {
                        deferred.reject(err);
                      } else {
                        dest.putInfo(data, function(err){
                          if(err) {
                            deferred.reject(err);
                          } else {
                            dest.stopWriting(function(err){
                              if(err) {
                                deferred.reject(err);
                              } else {
                                deferred.resolve();
                              }
                            });
                          }
                        });
                      }
                    });
                  }
                }
              });
            }
          });
        });
      }());
    });

    Q.all(sourceLoadingPromises).then(function() {
      debug("Finished loading sources");
      listen();
    }, function(err) {
      debug("Error loading sources");
      console.log(err);
      process.exit(-1);
    });
    sourceLoadingPromises = null;
  }

  function listen() {
    var ampqHost = process.env.AMPQ_HOST || "localhost";
    var server = 'amqp://' + ampqHost;
    var ampqTopic = process.env.AMPQ_TOPIC || "tiles";

    debug("Starting queue listener for " + server + "/" + ampqTopic);

    var queueContext = rabbit.createContext(server);
    queueContext.on('ready', function() {
      debug("Connected to context");
      var sub = queueContext.socket('WORKER', {prefetch: 2});
      sub.connect(ampqTopic, function() {
        debug("Connected to socket for " + ampqTopic);
        sub.on('data', function(note) {
          var subThis = this;
          debug("Received request " + note.toString());
          var messageComponents = note.toString().split("+");
          var sourceName = messageComponents[0];

          var tileComponents = messageComponents[1].split("/");
          var z = parseInt(tileComponents[0]);
          var startX, endX, startY, endY;
          var xComponents = tileComponents[1].split("-");
          if(xComponents.length == 1) {
            startX = endX = parseInt(xComponents[0]);
          } else {
            startX = parseInt(xComponents[0]);
            endX = parseInt(xComponents[1]);
          }

          var yComponents = tileComponents[2].split("-");
          if(yComponents.length == 1) {
            startY = endY = parseInt(yComponents[0]);
          } else {
            startY = parseInt(yComponents[0]);
            endY = parseInt(yComponents[1]);
          }

          var source = sources[sourceName];
          var dest = sinks[sourceName];
          debug("opening source " + config[sourceName]['destination'] + " for writing");
          dest.startWriting(function(err) {
            if(err) {
              console.log(err);
              throw err;
            }
            var tilePromises = [];

            for(var x = startX; x <= endX; x++) {
              for(var y = startY; y <= endY; y++) {
                (function(){
                  var tileX = x,
                    tileY = y,
                    tileZ = z,
                    deferred = Q.defer();

                  source.getTile(tileZ, tileX, tileY, function(err, tile, options) {
                    if(err) {
                      console.log(err);
                    } else {
                      debug("Rendered tile " + sourceName + "+" + tileZ + "/" + tileX + "/" + tileY);
                      dest.putTile(tileZ, tileX, tileY, tile, function(err){
                        if(err) {
                          console.log(err);
                          deferred.reject(err);
                        } else {
                          deferred.resolve();
                        }
                      });
                    }
                  });
                  tilePromises.push(deferred.promise);
                }());
              }
            }

            debug("Waiting for " + tilePromises.length + " tiles to render");
            Q.all(tilePromises).then(function() {
              debug("All tile promises resolved, closing source for writing");
              dest.stopWriting(function(err) {
                if(err) {
                  console.log(err);
                }
                subThis.ack();
              });
            }, function(err) {
              console.log("error resolving tile promises", err);
              subThis.ack();
            });
          });
        });
      });
    });
  }
};
<commit_msg>cleanup source loading callback hell, fixes #4<commit_after>#!/usr/bin/env node
"use strict";

// increase the libuv threadpool size to 1.5x the number of logical CPUs.
process.env.UV_THREADPOOL_SIZE = process.env.UV_THREADPOOL_SIZE ||
  Math.ceil(Math.max(4, require('os').cpus().length * 1.5));

var path = require("path"),
  debug = require("debug"),
  rabbit = require('rabbit.js'),
  Q = require("q");

debug = debug("tile-squirrel-cacher");

module.exports = function(opts) {
  var tilelive = require("tilelive");

  // load and register tilelive modules
  require("tilelive-modules/loader")(tilelive, opts);

  if (opts.uri) {
    throw "For now you must use a config file in queue mode";
  }

  //Load all sources
  var sources = {};
  var sinks = {};

  if (opts.config) {
    var config = require(path.resolve(opts.config));
    debug("Loading " + Object.keys(config).length + " sources");

    var sourceLoadingPromises = [];
    Object.keys(config).forEach(function(prefix) {
      (function(){
        var key = prefix;
        var deferred = Q.defer();
        sourceLoadingPromises.push(deferred.promise);
        tilelive.load(config[prefix]['source'], function(err, src){
          if(err) {
            console.log("Error loading source " + config[prefix]['source']);
            return deferred.reject(err);
          }
          sources[key] = src;
          tilelive.load(config[prefix]['destination'], function(err, dest){
            if(err) {
              console.log("Error loading destination " + config[prefix]['destination']);
              return deferred.reject(err);
            }
            sinks[key] = dest;
            src.getInfo(function(err, data){
              if(err){
                return deferred.reject(err);
              }
              if(data) {
                dest.startWriting(function(err){
                  if(err) {
                    return deferred.reject(err);
                  }
                  dest.putInfo(data, function(err){
                    if(err) {
                      return deferred.reject(err);
                    }
                    dest.stopWriting(function(err){
                      if(err) {
                        deferred.reject(err);
                      } else {
                        deferred.resolve();
                      }
                    });
                  });
                });
              }
            });
          });
        });
      }());
    });

    Q.all(sourceLoadingPromises).then(function() {
      debug("Finished loading sources");
      listen();
    }, function(err) {
      debug("Error loading sources");
      console.log(err);
      process.exit(-1);
    });
    sourceLoadingPromises = null;
  }

  function listen() {
    var ampqHost = process.env.AMPQ_HOST || "localhost";
    var server = 'amqp://' + ampqHost;
    var ampqTopic = process.env.AMPQ_TOPIC || "tiles";

    debug("Starting queue listener for " + server + "/" + ampqTopic);

    var queueContext = rabbit.createContext(server);
    queueContext.on('ready', function() {
      debug("Connected to context");
      var sub = queueContext.socket('WORKER', {prefetch: 2});
      sub.connect(ampqTopic, function() {
        debug("Connected to socket for " + ampqTopic);
        sub.on('data', function(note) {
          var subThis = this;
          debug("Received request " + note.toString());
          var messageComponents = note.toString().split("+");
          var sourceName = messageComponents[0];

          var tileComponents = messageComponents[1].split("/");
          var z = parseInt(tileComponents[0]);
          var startX, endX, startY, endY;
          var xComponents = tileComponents[1].split("-");
          if(xComponents.length == 1) {
            startX = endX = parseInt(xComponents[0]);
          } else {
            startX = parseInt(xComponents[0]);
            endX = parseInt(xComponents[1]);
          }

          var yComponents = tileComponents[2].split("-");
          if(yComponents.length == 1) {
            startY = endY = parseInt(yComponents[0]);
          } else {
            startY = parseInt(yComponents[0]);
            endY = parseInt(yComponents[1]);
          }

          var source = sources[sourceName];
          var dest = sinks[sourceName];
          debug("opening source " + config[sourceName]['destination'] + " for writing");
          dest.startWriting(function(err) {
            if(err) {
              console.log(err);
              throw err;
            }
            var tilePromises = [];

            for(var x = startX; x <= endX; x++) {
              for(var y = startY; y <= endY; y++) {
                (function(){
                  var tileX = x,
                    tileY = y,
                    tileZ = z,
                    deferred = Q.defer();

                  source.getTile(tileZ, tileX, tileY, function(err, tile, options) {
                    if(err) {
                      console.log(err);
                    } else {
                      debug("Rendered tile " + sourceName + "+" + tileZ + "/" + tileX + "/" + tileY);
                      dest.putTile(tileZ, tileX, tileY, tile, function(err){
                        if(err) {
                          console.log(err);
                          deferred.reject(err);
                        } else {
                          deferred.resolve();
                        }
                      });
                    }
                  });
                  tilePromises.push(deferred.promise);
                }());
              }
            }

            debug("Waiting for " + tilePromises.length + " tiles to render");
            Q.all(tilePromises).then(function() {
              debug("All tile promises resolved, closing source for writing");
              dest.stopWriting(function(err) {
                if(err) {
                  console.log(err);
                }
                subThis.ack();
              });
            }, function(err) {
              console.log("error resolving tile promises", err);
              subThis.ack();
            });
          });
        });
      });
    });
  }
};
<|endoftext|>


<commit_before>export const getMailSettings = () => ({
    url: 'settings/mail',
    method: 'get'
});

export const updateShowMoved = (ShowMoved) => ({
    url: 'settings/mail/moved',
    method: 'put',
    data: { ShowMoved }
});

export const updateShowImages = (ShowImages) => ({
    url: 'settings/mail/images',
    method: 'put',
    data: { ShowImages }
});

export const updateAutoSaveContacts = (AutoSaveContacts) => ({
    url: 'settings/mail/autocontacts',
    method: 'put',
    data: { AutoSaveContacts }
});

export const updateTheme = (Theme) => ({
    url: 'settings/mail/theme',
    method: 'put',
    data: { Theme }
});

export const updateDisplayName = (DisplayName) => ({
    url: 'settings/mail/display',
    method: 'put',
    data: { DisplayName }
});

export const updateSignature = (Signature) => ({
    url: 'settings/mail/signature',
    method: 'put',
    data: { Signature }
});

export const updatePMSignature = (PMSignature) => ({
    url: 'settings/mail/pmsignature',
    method: 'put',
    data: { PMSignature }
});

export const updateComposerMode = (ComposerMode) => ({
    url: 'settings/mail/composermode',
    method: 'put',
    data: { ComposerMode }
});

export const updateMessageButtons = (MessageButtons) => ({
    url: 'settings/mail/messagebuttons',
    method: 'put',
    data: { MessageButtons }
});

export const updateViewMode = (ViewMode) => ({
    url: 'settings/mail/viewmode',
    method: 'put',
    data: { ViewMode }
});

export const updateDraftType = (MIMEType) => ({
    url: 'settings/mail/drafttype',
    method: 'put',
    data: { MIMEType }
});

export const updateRightToLeft = (RightToLeft) => ({
    url: 'settings/mail/righttoleft',
    method: 'put',
    data: { RightToLeft }
});

export const updateViewLayout = (ViewLayout) => ({
    url: 'settings/mail/viewlayout',
    method: 'put',
    data: { ViewLayout }
});

export const updatePromptPin = (PromptPin) => ({
    url: 'settings/mail/promptpin',
    method: 'put',
    data: { PromptPin }
});

export const updateAutocrypt = (Autocrypt) => ({
    url: 'settings/mail/autocrypt',
    method: 'put',
    data: { Autocrypt }
});

export const updatePGPScheme = (PGPScheme) => ({
    url: 'settings/mail/pgpscheme',
    method: 'put',
    data: { PGPScheme }
});

export const updateSign = (Sign) => ({
    url: 'settings/mail/sign',
    method: 'put',
    data: { Sign }
});

export const updateAttachPublicKey = (AttachPublicKey) => ({
    url: 'settings/mail/attachpublic',
    method: 'put',
    data: { AttachPublicKey }
});

export const updateHotkeys = (Hotkeys) => ({
    url: 'settings/mail/hotkeys',
    method: 'put',
    data: { Hotkeys }
});
<commit_msg>Auto reply api endpoint (#16)<commit_after>export const getMailSettings = () => ({
    url: 'settings/mail',
    method: 'get'
});

export const updateShowMoved = (ShowMoved) => ({
    url: 'settings/mail/moved',
    method: 'put',
    data: { ShowMoved }
});

export const updateShowImages = (ShowImages) => ({
    url: 'settings/mail/images',
    method: 'put',
    data: { ShowImages }
});

export const updateAutoSaveContacts = (AutoSaveContacts) => ({
    url: 'settings/mail/autocontacts',
    method: 'put',
    data: { AutoSaveContacts }
});

export const updateTheme = (Theme) => ({
    url: 'settings/mail/theme',
    method: 'put',
    data: { Theme }
});

export const updateDisplayName = (DisplayName) => ({
    url: 'settings/mail/display',
    method: 'put',
    data: { DisplayName }
});

export const updateSignature = (Signature) => ({
    url: 'settings/mail/signature',
    method: 'put',
    data: { Signature }
});

export const updatePMSignature = (PMSignature) => ({
    url: 'settings/mail/pmsignature',
    method: 'put',
    data: { PMSignature }
});

export const updateComposerMode = (ComposerMode) => ({
    url: 'settings/mail/composermode',
    method: 'put',
    data: { ComposerMode }
});

export const updateMessageButtons = (MessageButtons) => ({
    url: 'settings/mail/messagebuttons',
    method: 'put',
    data: { MessageButtons }
});

export const updateViewMode = (ViewMode) => ({
    url: 'settings/mail/viewmode',
    method: 'put',
    data: { ViewMode }
});

export const updateDraftType = (MIMEType) => ({
    url: 'settings/mail/drafttype',
    method: 'put',
    data: { MIMEType }
});

export const updateRightToLeft = (RightToLeft) => ({
    url: 'settings/mail/righttoleft',
    method: 'put',
    data: { RightToLeft }
});

export const updateViewLayout = (ViewLayout) => ({
    url: 'settings/mail/viewlayout',
    method: 'put',
    data: { ViewLayout }
});

export const updatePromptPin = (PromptPin) => ({
    url: 'settings/mail/promptpin',
    method: 'put',
    data: { PromptPin }
});

export const updateAutocrypt = (Autocrypt) => ({
    url: 'settings/mail/autocrypt',
    method: 'put',
    data: { Autocrypt }
});

export const updatePGPScheme = (PGPScheme) => ({
    url: 'settings/mail/pgpscheme',
    method: 'put',
    data: { PGPScheme }
});

export const updateSign = (Sign) => ({
    url: 'settings/mail/sign',
    method: 'put',
    data: { Sign }
});

export const updateAttachPublicKey = (AttachPublicKey) => ({
    url: 'settings/mail/attachpublic',
    method: 'put',
    data: { AttachPublicKey }
});

export const updateHotkeys = (Hotkeys) => ({
    url: 'settings/mail/hotkeys',
    method: 'put',
    data: { Hotkeys }
});

export const updateAutoresponder = (AutoResponder) => ({
    url: 'settings/mail/autoresponder',
    method: 'put',
    data: { AutoResponder }
});
<|endoftext|>


<commit_before>(function(){

  var FRAME_DURATION = 1e3/60,
      SUSPEND_THRESHOLD = FRAME_DURATION * 30;

  var _ = require('lodash'),
      THREE = require('three'),
      Stats = require('stats.js'),
      EE = require('events').EventEmitter,
      Composer = require('./composer'),
      inherits = require('util').inherits,
      now = require('./common/now');

  function Canvas(el, Scene, lumine, options){

    this.opts = options || {};

    this.playing = false;

    this.cTime = null;
    this.pTime = null;
    this.sTime = null;

    // bind to and prepare DOM element

    if(el){

      this.el = el;
      this.el.classList.add('lumine');

      this.renderer = new THREE.WebGLRenderer({
        canvas: this.el,
        antialias: true
      });

      window.addEventListener('resize', function(){
        this.needsResize = true;
      }.bind(this));

      // prepare a stat watcher

      this.stats = new Stats();
      this.stats.setMode(0);

      this.stats.domElement.classList.add('lumine-stats');

      document.body.appendChild(this.stats.domElement);

      this.renderer.setClearColor(0xffffff, 0);

    }

    this.composer = new Composer(el ? this.renderer : this.opts.renderer, el ? undefined: this.opts);

    this.querySize();

    _.each(Scene.layers, function(layer, i){

      var layerPass = lumine.Layers[layer.type](Scene, this, lumine, layer);

      if(this.el && i === Scene.layers.length - 1){
        layerPass.renderToScreen = true;
      }else{
        layerPass.needsSwap = true;
      }

      this.composer.addPass( layerPass );

    }.bind(this));

    EE.call(this);

  }

  inherits(Canvas, EE);

  Canvas.prototype.querySize = function(){

    if(this.el){

      var box = this.el.getBoundingClientRect(),
          density = window.devicePixelRatio;

      this.setSize(box.width, box.height, density);

    }

  };

  Canvas.prototype.setSize = function(width, height, density){

    this.size = {
      width: width,
      height: height,
      density: density
    };

    this.density = density;

    if(this.el){

      this.renderer.setPixelRatio(density);
      this.renderer.setSize(this.size.width, this.size.height, this.opts.useStyle || false);

    }

    this.composer.setSize(this.size.width * density, this.size.height * density);

  };

  Canvas.prototype.render = function(){
    var self = this;

    if(this.stats) this.stats.begin();

    if(this.needsResize){

      if(this.el) this.querySize();

      this.emit('resize');
      this.needsResize = false;

    }

    this.cTime = now();

    var delta = this.cTime - this.pTime < SUSPEND_THRESHOLD ? (this.cTime - this.pTime) : FRAME_DURATION;

    this.emit('pre-render', delta);

    this.composer.render( delta );

    this.emit('render', delta);

    if(this.stats) this.stats.end();

    if(this.playing){
      requestAnimationFrame(function(){
        self.render.apply(self, arguments);
      });
    }

  };

  Canvas.prototype.start = function(){
    var self = this;

    this.playing = true;

    this.sTime = this.pTime = this.cTime = now();

    requestAnimationFrame(function(){
      self.render.apply(self, arguments);
    });

  };

  Canvas.prototype.pause = function(){
    this.playing = false;
  };

  module.exports = Canvas;

})();<commit_msg>Changing parameter passing.<commit_after>(function(){

  var FRAME_DURATION = 1e3/60,
      SUSPEND_THRESHOLD = FRAME_DURATION * 30;

  var _ = require('lodash'),
      THREE = require('three'),
      Stats = require('stats.js'),
      EE = require('events').EventEmitter,
      Composer = require('./composer'),
      inherits = require('util').inherits,
      now = require('./common/now');

  function Canvas(el, Scene, lumine, options){

    this.opts = options || {};

    this.playing = false;

    this.cTime = null;
    this.pTime = null;
    this.sTime = null;

    // bind to and prepare DOM element

    if(el){

      this.el = el;
      this.el.classList.add('lumine');

      this.renderer = new THREE.WebGLRenderer({
        canvas: this.el,
        antialias: true
      });

      window.addEventListener('resize', function(){
        this.needsResize = true;
      }.bind(this));

      // prepare a stat watcher

      this.stats = new Stats();
      this.stats.setMode(0);

      this.stats.domElement.classList.add('lumine-stats');

      document.body.appendChild(this.stats.domElement);

      this.renderer.setClearColor(0xffffff, 0);

      this.composer = new Composer(this.renderer);

    }else{

      this.composer = new Composer(this.opts.renderer, this.opts);

      this.setSize(this.opts.width, this.opts.height, this.opts.density);

    }

    this.querySize();

    _.each(Scene.layers, function(layer, i){

      var layerPass = lumine.Layers[layer.type](Scene, this, lumine, layer);

      if(this.el && i === Scene.layers.length - 1){
        layerPass.renderToScreen = true;
      }else{
        layerPass.needsSwap = true;
      }

      this.composer.addPass( layerPass );

    }.bind(this));

    EE.call(this);

  }

  inherits(Canvas, EE);

  Canvas.prototype.querySize = function(){

    if(this.el){

      var box = this.el.getBoundingClientRect(),
          density = window.devicePixelRatio;

      this.setSize(box.width, box.height, density);

    }

  };

  Canvas.prototype.setSize = function(width, height, density){

    this.size = {
      width: width,
      height: height
    };

    this.density = density || 1;

    if(this.el){

      this.renderer.setPixelRatio(this.density);
      this.renderer.setSize(this.size.width, this.size.height, this.opts.useStyle || false);

    }

    this.composer.setSize(this.size.width * this.density, this.size.height * this.density);

  };

  Canvas.prototype.render = function(){
    var self = this;

    if(this.stats) this.stats.begin();

    if(this.needsResize){

      if(this.el) this.querySize();

      this.emit('resize');
      this.needsResize = false;

    }

    this.cTime = now();

    var delta = this.cTime - this.pTime < SUSPEND_THRESHOLD ? (this.cTime - this.pTime) : FRAME_DURATION;

    this.emit('pre-render', delta);

    this.composer.render( delta );

    this.emit('render', delta);

    if(this.stats) this.stats.end();

    if(this.playing){
      requestAnimationFrame(function(){
        self.render.apply(self, arguments);
      });
    }

  };

  Canvas.prototype.start = function(){
    var self = this;

    this.playing = true;

    this.sTime = this.pTime = this.cTime = now();

    requestAnimationFrame(function(){
      self.render.apply(self, arguments);
    });

  };

  Canvas.prototype.pause = function(){
    this.playing = false;
  };

  module.exports = Canvas;

})();<|endoftext|>


<commit_before>import '../findParameter'

function processPathParameter(app, parameters, name, pattern, optional) {
	let parameter = findParameter(parameters, name)

	if(parameter === null) {
		const binding = app.routes.bindings[name]

		if(!binding.isNil && !binding.context.isNil && !binding.context.swagger.isNil) {
			parameter = Object.assign({ }, app.routes.bindings[name].context.swagger)
			parameters.push(parameter)
		}
	}

	if(parameter !== null) {
		if(typeof pattern === 'string') {
			parameter.pattern = pattern
		}

		if(parameter.required.isNil) {
			parameter.required = optional !== '?'
		}

		if(parameter.in.isNil) {
			parameter.in = 'url'
		}
	}

	return `{${name}}`
}

export function route(path, app, parameters) {
	return path.replace(/:([a-z0-0_\-\.]+)(?:\(([^\)]+)\))?(\?)?/g, (...args) => {
		args.shift()
		return processPathParameter(app, parameters, ...args)
	})
}
<commit_msg>Fixed lint errors in route.js<commit_after>import '../findParameter'

function processPathParameter(app, parameters, name, pattern, optional) {
	let parameter = findParameter(parameters, name)

	if(parameter === null) {
		const binding = app.routes.bindings[name]

		if(!binding.isNil && !binding.context.isNil && !binding.context.swagger.isNil) {
			parameter = Object.assign({ }, app.routes.bindings[name].context.swagger)
			parameters.push(parameter)
		}
	}

	if(parameter !== null) {
		if(typeof pattern === 'string') {
			parameter.pattern = pattern
		}

		if(parameter.required.isNil) {
			parameter.required = optional !== '?'
		}

		if(parameter.in.isNil) {
			parameter.in = 'url'
		}
	}

	return `{${name}}`
}

export function route(path, app, parameters) {
	return path.replace(/:([a-z0-0_\-.]+)(?:\(([^)]+)\))?(\?)?/g, (...args) => {
		args.shift()
		return processPathParameter(app, parameters, ...args)
	})
}
<|endoftext|>


<commit_before>/*
 * ChordProJS - Parse and render ChordPro formatted songs.
 * Copyright (c) 2016 Tom Davies
 *
 * chords.js
 * Module for processing chords in song, handling key detection and chord transposition.
 */

var _ = require('lodash'),
    chordMagic = require('chord-magic');

var notes = ['A', 'Bb', 'B', 'C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab'];
var sharps = ['A', 'B', 'D', 'E', 'G'];
var intervals = [
    { step: 2, minor: true },
    { step: 2, minor: true },
    { step: 1 },
    { step: 2 },
    { step: 2, minor: true },
    { step: 2 },
    { step: 1 }
];

function getEnharmonicEquivalent(chordText) {
    var idx = notes.indexOf(chordText.substring(0, 2)) - 1;

    if (idx < 0) {
        idx = notes.length - 1;
    }

    return notes[idx] + '#' + chordText.substring(2);
}

function getTranspose(origKey, targetKey) {
    var origKeyIdx = notes.indexOf(origKey);
    var targetKeyIdx = notes.indexOf(targetKey);

    if (origKeyIdx > -1 && targetKeyIdx > -1) {
        return targetKeyIdx - origKeyIdx;
    }

    return 0;
}

function getNoteInterval(note, interval) {
    var i = notes.indexOf(note) + interval;

    if (i >= notes.length) {
        i = i - notes.length;
    }

    return notes[i];
}

function getScale(note, minor) {
    var intervals = minor ? intervalsMinor : intervalsMajor;
    var scale = [note];
    var prevNote = note;

    intervals.forEach(function (interval) {
        prevNote = getNoteInterval(prevNote, interval.step);
        scale.push(prevNote);
    });

    return scale;
}

function getKeysContainingChord(chord) {
    var keys = [];

    notes.forEach(function (key) {
        var note = key;
        // For each key, go over each chord and check for match
        intervals.forEach(function (interval) {
            note = getNoteInterval(note, interval.step);
            var noteChord = note + (interval.minor ? 'm' : '');
            if (chord === noteChord) {
                // Add this key to keys
                keys.push(key);
                return;
            }
        });
    });

    return keys;
}

function getRootNote(chord) {
    var note = chord.charAt(0);
    var intonation = chord.charAt(1);

    if (intonation === '#') {
        intonation = 'b';
        note = getNoteInterval(note, 2);
    } else if (intonation !== 'b') {
        intonation = '';
    }

    return note + intonation;
}

function findKey(chords) {
    var keys = _.countBy(_.flatten(chords.map(function (chord) {
        var note = getRootNote(chord);
        var chord = chord.substring(note.length);
        if ((chord.indexOf('m') === 0 && chord.indexOf('maj') !== 0) || chord.indexOf('min') === 0) {
            note = note + 'm';
        }

        return getKeysContainingChord(note);
    })));

    // Return the most likely (most frequent) key for the chords passed in.
    return _.maxBy(_.map(keys, function (val, key) {
        return {key: key, count: val};
    }), 'count').key;
}

function Chord(chordText, transposeProperties) {
    this.transposeProperties = transposeProperties;
    this.chordMagicked = chordMagic.parse(chordText);
}

Chord.prototype.getText = function () {
    var chord = this.chordMagicked;
    var transpose = this.transposeProperties.transpose;

    if (this.transposeProperties.targetKey !== null) {
        // Work out transpose from original key
        transpose = getTranspose(this.transposeProperties.origKey, this.transposeProperties.targetKey);
    } else {
        // Get the target key from the transpose
        this.transposeProperties.targetKey = chordMagic.prettyPrint(chordMagic.transpose(chordMagic.parse(this.transposeProperties.origKey), transpose));
    }

    if (transpose !== 0) {
        chord = chordMagic.transpose(this.chordMagicked, transpose);
    }

    var chordText = chordMagic.prettyPrint(chord);

    if (chordText.length > 1 && chordText.charAt(1) === 'b' && sharps.indexOf(this.transposeProperties.targetKey) > -1) {
        chordText = getEnharmonicEquivalent(chordText);
    }

    return chordText;
};

Chord.prototype.getOrigText = function () {
    return chordMagic.prettyPrint(this.chordMagicked);
};

function Chords() {
    this.chords = [];
    this.transposeProperties = {
        origKey: '',
        targetKey: null,
        transpose: 0
    };
}

Chords.prototype.getOrigKey = function () {
    return this.transposeProperties.origKey;
};

Chords.prototype.getTargetKey = function () {
    return this.transposeProperties.targetKey;
};

Chords.prototype.setTargetKey = function (targetKey) {
    targetKey = chordMagic.parse(targetKey).root;
    if (notes.indexOf(targetKey) > -1) {
        this.transposeProperties.targetKey = targetKey;
    }
};

Chords.prototype.setTranspose = function (transpose) {
    this.transposeProperties.transpose = transpose;
    this.transposeProperties.targetKey = null;
};

Chords.prototype.createChord = function (chordText) {
    var chord = new Chord(chordText, this.transposeProperties);
    this.chords.push(chord);
    // Detect key
    this.transposeProperties.origKey = findKey(this.chords.map(function (chord) {
        return chord.getOrigText();
    }));
    return chord;
};

module.exports = Chords;<commit_msg>Update chords.js<commit_after>/*
 * ChordProJS - Parse and render ChordPro formatted songs.
 * Copyright (c) 2016 Tom Davies
 *
 * chords.js
 * Module for processing chords in song, handling key detection and chord transposition.
 */

var _ = require('lodash'),
    chordMagic = require('chord-magic');

var notes = ['A', 'Bb', 'B', 'C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab'];
var sharps = ['A', 'B', 'D', 'E', 'G'];
var intervals = [
    { step: 2, minor: true },
    { step: 2, minor: true },
    { step: 1 },
    { step: 2 },
    { step: 2, minor: true },
    { step: 2 },
    { step: 1 }
];

function getSharpEquivalent(chordText) {
    return chordText.split("/").map(function (val) {
        if (val.indexOf('b') === 1) {
          var idx = notes.indexOf(val.substring(0, 2)) - 1;

          if (idx < 0) {
              idx = notes.length - 1;
          }

          return notes[idx] + '#' + val.substring(2);
        }

        return val;
    }).join("/");
}

function getTranspose(origKey, targetKey) {
    var origKeyIdx = notes.indexOf(origKey);
    var targetKeyIdx = notes.indexOf(targetKey);

    if (origKeyIdx > -1 && targetKeyIdx > -1) {
        return targetKeyIdx - origKeyIdx;
    }

    return 0;
}

function getNoteInterval(note, interval) {
    var i = notes.indexOf(note) + interval;

    if (i >= notes.length) {
        i = i - notes.length;
    }

    return notes[i];
}

function getScale(note, minor) {
    var intervals = minor ? intervalsMinor : intervalsMajor;
    var scale = [note];
    var prevNote = note;

    intervals.forEach(function (interval) {
        prevNote = getNoteInterval(prevNote, interval.step);
        scale.push(prevNote);
    });

    return scale;
}

function getKeysContainingChord(chord) {
    var keys = [];

    notes.forEach(function (key) {
        var note = key;
        // For each key, go over each chord and check for match
        intervals.forEach(function (interval) {
            note = getNoteInterval(note, interval.step);
            var noteChord = note + (interval.minor ? 'm' : '');
            if (chord === noteChord) {
                // Add this key to keys
                keys.push(key);
                return;
            }
        });
    });

    return keys;
}

function getRootNote(chord) {
    var note = chord.charAt(0);
    var intonation = chord.charAt(1);

    if (intonation === '#') {
        intonation = 'b';
        note = getNoteInterval(note, 2);
    } else if (intonation !== 'b') {
        intonation = '';
    }

    return note + intonation;
}

function findKey(chords) {
    var keys = _.countBy(_.flatten(chords.map(function (chord) {
        var note = getRootNote(chord);
        var chord = chord.substring(note.length);
        if ((chord.indexOf('m') === 0 && chord.indexOf('maj') !== 0) || chord.indexOf('min') === 0) {
            note = note + 'm';
        }

        return getKeysContainingChord(note);
    })));

    // Return the most likely (most frequent) key for the chords passed in.
    return _.maxBy(_.map(keys, function (val, key) {
        return {key: key, count: val};
    }), 'count').key;
}

function Chord(chordText, transposeProperties) {
    this.transposeProperties = transposeProperties;
    this.chordMagicked = chordMagic.parse(chordText);
}

Chord.prototype.getText = function () {
    var chord = this.chordMagicked;
    var transpose = this.transposeProperties.transpose;

    if (this.transposeProperties.targetKey !== null) {
        // Work out transpose from original key
        transpose = getTranspose(this.transposeProperties.origKey, this.transposeProperties.targetKey);
    } else {
        // Get the target key from the transpose
        this.transposeProperties.targetKey = chordMagic.prettyPrint(chordMagic.transpose(chordMagic.parse(this.transposeProperties.origKey), transpose));
    }

    if (transpose !== 0) {
        chord = chordMagic.transpose(this.chordMagicked, transpose);
    }

    var chordText = chordMagic.prettyPrint(chord);

    if (chordText.length > 1 && chordText.indexOf('b') > -1 && sharps.indexOf(this.transposeProperties.targetKey) > -1) {
        chordText = getSharpEquivalent(chordText);
    }

    return chordText;
};

Chord.prototype.getOrigText = function () {
    return chordMagic.prettyPrint(this.chordMagicked);
};

function Chords() {
    this.chords = [];
    this.transposeProperties = {
        origKey: '',
        targetKey: null,
        transpose: 0
    };
}

Chords.prototype.getOrigKey = function () {
    return this.transposeProperties.origKey;
};

Chords.prototype.getTargetKey = function () {
    return this.transposeProperties.targetKey;
};

Chords.prototype.setTargetKey = function (targetKey) {
    targetKey = chordMagic.parse(targetKey).root;
    if (notes.indexOf(targetKey) > -1) {
        this.transposeProperties.targetKey = targetKey;
    }
};

Chords.prototype.setTranspose = function (transpose) {
    this.transposeProperties.transpose = transpose;
    this.transposeProperties.targetKey = null;
};

Chords.prototype.createChord = function (chordText) {
    var chord = new Chord(chordText, this.transposeProperties);
    this.chords.push(chord);
    // Detect key
    this.transposeProperties.origKey = findKey(this.chords.map(function (chord) {
        return chord.getOrigText();
    }));
    return chord;
};

module.exports = Chords;
<|endoftext|>


<commit_before>var defaults = require('./defaults.js');
var devtools = require('./devtools.js');
var util = require('util');
var events = require('events');
var WebSocket = require('ws');

function Chrome(options, notifier) {
    var self = this;
    // options
    options = options || {};
    self.host = options.host || defaults.HOST;
    self.port = options.port || defaults.PORT;
    self.protocol = options.protocol;
    self.remote = !!(options.remote);
    self.chooseTab = options.chooseTab || function () { return 0; };
    // locals
    events.EventEmitter.call(this);
    self.notifier = notifier;
    self.callbacks = {};
    self.nextCommandId = 1;
    // operations
    connectToChrome.call(self);
}

util.inherits(Chrome, events.EventEmitter);

Chrome.prototype.inspect = function (depth, options) {
    options.customInspect = false;
    return util.inspect(this, options);
};

Chrome.prototype.send = function (method, params, callback) {
    var self = this;
    if (typeof params === 'function') {
        callback = params;
        params = undefined;
    }
    // return a promise when a callback is not provided
    if (typeof callback === 'function') {
        enqueueCommand.call(self, method, params, callback);
    } else {
        return new Promise(function (fulfill, reject) {
            enqueueCommand.call(self, method, params, function (error, response) {
                if (error) {
                    reject(response);
                } else {
                    fulfill(response);
                }
            });
        });
    }
};

Chrome.prototype.close = function (callback) {
    var self = this;
    function closeWebSocket(callback) {
        // don't notify on user-initiated shutdown ('disconnect' event)
        self.ws.removeAllListeners('close');
        self.ws.close();
        self.ws.once('close', function () {
            self.ws.removeAllListeners();
            callback();
        });
    }
    if (typeof callback === 'function') {
        closeWebSocket(callback);
    } else {
        return new Promise(function (fulfill, reject) {
            closeWebSocket(fulfill);
        });
    }
};

function enqueueCommand(method, params, callback) {
    var self = this;
    var id = self.nextCommandId++;
    var message = {'id': id, 'method': method, 'params': params};
    self.ws.send(JSON.stringify(message));
    self.callbacks[id] = callback;
}

function arrayToObject(parameters) {
    var keyValue = {};
    parameters.forEach(function (parameter) {
        var name = parameter.name;
        delete parameter.name;
        keyValue[name] = parameter;
    });
    return keyValue;
}

function decorate(to, category, object) {
    to.category = category;
    for (var field in object) {
        // commands and events have parameters whereas types have properties
        if (category === 'type' && field === 'properties' ||
            field === 'parameters') {
            to[field] = arrayToObject(object[field]);
        } else {
            to[field] = object[field];
        }
    }
}

function addCommand(domainName, command) {
    var self = this;
    var handler = function (params, callback) {
        return self.send(domainName + '.' + command.name, params, callback);
    };
    decorate(handler, 'command', command);
    self[domainName][command.name] = handler;
}

function addEvent(domainName, event) {
    var self = this;
    var handler = function (handler) {
        self.on(domainName + '.' + event.name, handler);
    };
    decorate(handler, 'event', event);
    self[domainName][event.name] = handler;
}

function addType(domainName, type) {
    var self = this;
    var help = {};
    decorate(help, 'type', type);
    self[domainName][type.id] = help;
}

function addCommandShorthands() {
    var self = this;
    for (var domainIdx in self.protocol.domains) {
        var domain = self.protocol.domains[domainIdx];
        var domainName = domain.domain;
        self[domainName] = {};
        // add commands
        var commands = domain.commands;
        if (commands) {
            for (var commandIdx in commands) {
                var command = commands[commandIdx];
                addCommand.call(self, domainName, command);
            }
        }
        // add events
        var events = domain.events;
        if (events) {
            for (var eventIdx in events) {
                var event = events[eventIdx];
                addEvent.call(self, domainName, event);
            }
        }
        // add types
        var types = domain.types;
        if (types) {
            for (var typeIdx in types) {
                var type = types[typeIdx];
                addType.call(self, domainName, type);
            }
        }
    }
}

function connectToChrome() {
    var self = this;
    var options = {'host': self.host, 'port': self.port};
    // fetch the WebSocket debugger URL from the user choice (`chooseTab`)
    var fetchDebuggerURL = function (callback) {
        // when DevTools are open or another WebSocket is connected to a given
        // tab the `webSocketDebuggerUrl` filed is not available
        var busyTabError = new Error('Tab does not support inspection');
        var url;
        switch (typeof self.chooseTab) {
        case 'string':
            // a WebSocket URL is specified by the user (e.g., node-inspector)
            callback(null, self.chooseTab);
            break;
        case 'object':
            // a tab object is specified by the user
            url = self.chooseTab.webSocketDebuggerUrl;
            if (url) {
                callback(null, url);
            } else {
                callback(busyTabError);
            }
            break;
        case 'function':
            // a function is specified by the user (get tab by index)
            devtools.List(options, function (err, tabs) {
                if (err) {
                    callback(err);
                } else {
                    // the index is used to fetch the proper tab from the list
                    var tab = tabs[self.chooseTab(tabs)];
                    if (tab) {
                        url = tab.webSocketDebuggerUrl;
                        if (url) {
                            callback(null, url);
                        } else {
                            callback(busyTabError);
                        }
                    } else {
                        callback(new Error('Invalid tab index'));
                    }
                }
            });
            break;
        default:
            callback(new Error('Invalid requested tab'));
        }
    };
    // parse the protocol and finalize connection
    var continueConnection = function () {
        // build the API from the protocol descriptor
        addCommandShorthands.call(self);
        // get the WebSocket debugger URL
        fetchDebuggerURL(function (err, url) {
            if (err) {
                self.notifier.emit('error', err);
            } else {
                connectToWebSocket.call(self, url);
            }
        });
    };
    // if a protocol has been provided then use it
    if (self.protocol) {
        continueConnection();
    } else {
        // otherwise user either the local or the remote version
        options.remote = self.remote;
        devtools.Protocol(options, function (err, protocol) {
            if (err) {
                self.notifier.emit('error', err);
            } else {
                self.protocol = protocol.descriptor;
                continueConnection();
            }
        });
    }
}

function connectToWebSocket(url) {
    var self = this;
    // disable the permessage-deflate as a temporary fix for #39
    self.ws = new WebSocket(url, {'perMessageDeflate': false});
    self.ws.on('open', function () {
        self.notifier.emit('connect', self);
    });
    self.ws.on('message', function (data) {
        var message = JSON.parse(data);
        // command response
        if (message.id) {
            var callback = self.callbacks[message.id];
            if (callback) {
                // interpret the lack of both 'error' and 'result' as success
                // (this may happen with node-inspector)
                if (message.error) {
                    callback(true, message.error);
                } else {
                    callback(false, message.result || {});
                }
                // unregister command response callback
                delete self.callbacks[message.id];
                // notify when there are no more pending commands
                if (Object.keys(self.callbacks).length === 0) {
                    self.emit('ready');
                }
            }
        }
        // event
        else if (message.method) {
            self.emit('event', message);
            self.emit(message.method, message.params);
        }
    });
    self.ws.on('close', function () {
        self.notifier.emit('disconnect');
    });
    self.ws.on('error', function (err) {
        self.notifier.emit('error', err);
    });
}

module.exports = Chrome;
<commit_msg>Properly handle the WebSocket creation error<commit_after>var defaults = require('./defaults.js');
var devtools = require('./devtools.js');
var util = require('util');
var events = require('events');
var WebSocket = require('ws');

function Chrome(options, notifier) {
    var self = this;
    // options
    options = options || {};
    self.host = options.host || defaults.HOST;
    self.port = options.port || defaults.PORT;
    self.protocol = options.protocol;
    self.remote = !!(options.remote);
    self.chooseTab = options.chooseTab || function () { return 0; };
    // locals
    events.EventEmitter.call(this);
    self.notifier = notifier;
    self.callbacks = {};
    self.nextCommandId = 1;
    // operations
    connectToChrome.call(self);
}

util.inherits(Chrome, events.EventEmitter);

Chrome.prototype.inspect = function (depth, options) {
    options.customInspect = false;
    return util.inspect(this, options);
};

Chrome.prototype.send = function (method, params, callback) {
    var self = this;
    if (typeof params === 'function') {
        callback = params;
        params = undefined;
    }
    // return a promise when a callback is not provided
    if (typeof callback === 'function') {
        enqueueCommand.call(self, method, params, callback);
    } else {
        return new Promise(function (fulfill, reject) {
            enqueueCommand.call(self, method, params, function (error, response) {
                if (error) {
                    reject(response);
                } else {
                    fulfill(response);
                }
            });
        });
    }
};

Chrome.prototype.close = function (callback) {
    var self = this;
    function closeWebSocket(callback) {
        // don't notify on user-initiated shutdown ('disconnect' event)
        self.ws.removeAllListeners('close');
        self.ws.close();
        self.ws.once('close', function () {
            self.ws.removeAllListeners();
            callback();
        });
    }
    if (typeof callback === 'function') {
        closeWebSocket(callback);
    } else {
        return new Promise(function (fulfill, reject) {
            closeWebSocket(fulfill);
        });
    }
};

function enqueueCommand(method, params, callback) {
    var self = this;
    var id = self.nextCommandId++;
    var message = {'id': id, 'method': method, 'params': params};
    self.ws.send(JSON.stringify(message));
    self.callbacks[id] = callback;
}

function arrayToObject(parameters) {
    var keyValue = {};
    parameters.forEach(function (parameter) {
        var name = parameter.name;
        delete parameter.name;
        keyValue[name] = parameter;
    });
    return keyValue;
}

function decorate(to, category, object) {
    to.category = category;
    for (var field in object) {
        // commands and events have parameters whereas types have properties
        if (category === 'type' && field === 'properties' ||
            field === 'parameters') {
            to[field] = arrayToObject(object[field]);
        } else {
            to[field] = object[field];
        }
    }
}

function addCommand(domainName, command) {
    var self = this;
    var handler = function (params, callback) {
        return self.send(domainName + '.' + command.name, params, callback);
    };
    decorate(handler, 'command', command);
    self[domainName][command.name] = handler;
}

function addEvent(domainName, event) {
    var self = this;
    var handler = function (handler) {
        self.on(domainName + '.' + event.name, handler);
    };
    decorate(handler, 'event', event);
    self[domainName][event.name] = handler;
}

function addType(domainName, type) {
    var self = this;
    var help = {};
    decorate(help, 'type', type);
    self[domainName][type.id] = help;
}

function addCommandShorthands() {
    var self = this;
    for (var domainIdx in self.protocol.domains) {
        var domain = self.protocol.domains[domainIdx];
        var domainName = domain.domain;
        self[domainName] = {};
        // add commands
        var commands = domain.commands;
        if (commands) {
            for (var commandIdx in commands) {
                var command = commands[commandIdx];
                addCommand.call(self, domainName, command);
            }
        }
        // add events
        var events = domain.events;
        if (events) {
            for (var eventIdx in events) {
                var event = events[eventIdx];
                addEvent.call(self, domainName, event);
            }
        }
        // add types
        var types = domain.types;
        if (types) {
            for (var typeIdx in types) {
                var type = types[typeIdx];
                addType.call(self, domainName, type);
            }
        }
    }
}

function connectToChrome() {
    var self = this;
    var options = {'host': self.host, 'port': self.port};
    // fetch the WebSocket debugger URL from the user choice (`chooseTab`)
    var fetchDebuggerURL = function (callback) {
        // when DevTools are open or another WebSocket is connected to a given
        // tab the `webSocketDebuggerUrl` filed is not available
        var busyTabError = new Error('Tab does not support inspection');
        var url;
        switch (typeof self.chooseTab) {
        case 'string':
            // a WebSocket URL is specified by the user (e.g., node-inspector)
            callback(null, self.chooseTab);
            break;
        case 'object':
            // a tab object is specified by the user
            url = self.chooseTab.webSocketDebuggerUrl;
            if (url) {
                callback(null, url);
            } else {
                callback(busyTabError);
            }
            break;
        case 'function':
            // a function is specified by the user (get tab by index)
            devtools.List(options, function (err, tabs) {
                if (err) {
                    callback(err);
                } else {
                    // the index is used to fetch the proper tab from the list
                    var tab = tabs[self.chooseTab(tabs)];
                    if (tab) {
                        url = tab.webSocketDebuggerUrl;
                        if (url) {
                            callback(null, url);
                        } else {
                            callback(busyTabError);
                        }
                    } else {
                        callback(new Error('Invalid tab index'));
                    }
                }
            });
            break;
        default:
            callback(new Error('Invalid requested tab'));
        }
    };
    // parse the protocol and finalize connection
    var continueConnection = function () {
        // build the API from the protocol descriptor
        addCommandShorthands.call(self);
        // get the WebSocket debugger URL
        fetchDebuggerURL(function (err, url) {
            if (err) {
                self.notifier.emit('error', err);
            } else {
                connectToWebSocket.call(self, url);
            }
        });
    };
    // if a protocol has been provided then use it
    if (self.protocol) {
        continueConnection();
    } else {
        // otherwise user either the local or the remote version
        options.remote = self.remote;
        devtools.Protocol(options, function (err, protocol) {
            if (err) {
                self.notifier.emit('error', err);
            } else {
                self.protocol = protocol.descriptor;
                continueConnection();
            }
        });
    }
}

function connectToWebSocket(url) {
    var self = this;
    try {
        // disable the permessage-deflate as a temporary fix for #39
        self.ws = new WebSocket(url, {'perMessageDeflate': false});
    } catch (err) {
        self.notifier.emit('error', err);
        return;
    }
    self.ws.on('open', function () {
        self.notifier.emit('connect', self);
    });
    self.ws.on('message', function (data) {
        var message = JSON.parse(data);
        // command response
        if (message.id) {
            var callback = self.callbacks[message.id];
            if (callback) {
                // interpret the lack of both 'error' and 'result' as success
                // (this may happen with node-inspector)
                if (message.error) {
                    callback(true, message.error);
                } else {
                    callback(false, message.result || {});
                }
                // unregister command response callback
                delete self.callbacks[message.id];
                // notify when there are no more pending commands
                if (Object.keys(self.callbacks).length === 0) {
                    self.emit('ready');
                }
            }
        }
        // event
        else if (message.method) {
            self.emit('event', message);
            self.emit(message.method, message.params);
        }
    });
    self.ws.on('close', function () {
        self.notifier.emit('disconnect');
    });
    self.ws.on('error', function (err) {
        self.notifier.emit('error', err);
    });
}

module.exports = Chrome;
<|endoftext|>


<commit_before>import {Transform} from 'vega-dataflow';
import {error, inherits} from 'vega-util';
import {stratify} from 'd3-hierarchy';

 /**
  * Stratify a collection of tuples into a tree structure based on
  * id and parent id fields.
  * @constructor
  * @param {object} params - The parameters for this operator.
  * @param {function(object): *} params.key - Unique key field for each tuple.
  * @param {function(object): *} params.parentKey - Field with key for parent tuple.
  */
export default function Stratify(params) {
  Transform.call(this, null, params);
}

Stratify.Definition = {
  "type": "Stratify",
  "metadata": {"treesource": true},
  "params": [
    { "name": "key", "type": "field", "required": true },
    { "name": "parentKey", "type": "field", "required": true  }
  ]
};

var prototype = inherits(Stratify, Transform);

prototype.transform = function(_, pulse) {
  if (!pulse.source) {
    error('Stratify transform requires an upstream data source.');
  }

  var mod = _.modified(), tree, map,
      run = !this.value
         || mod
         || pulse.changed(pulse.ADD_REM)
         || pulse.modified(_.key.fields)
         || pulse.modified(_.parentKey.fields);

  if (run) {
    tree = stratify().id(_.key).parentId(_.parentKey)(pulse.source);
    map = tree.lookup = {};
    tree.each(function(node) { map[_.key(node.data)] = node; });
    this.value = tree;
  }

  pulse.source.root = this.value;
  return mod ? pulse.fork(pulse.ALL) : pulse;
};
<commit_msg>Fix pulse handling by Stratify transform.<commit_after>import {Transform} from 'vega-dataflow';
import {error, inherits} from 'vega-util';
import {stratify} from 'd3-hierarchy';

 /**
  * Stratify a collection of tuples into a tree structure based on
  * id and parent id fields.
  * @constructor
  * @param {object} params - The parameters for this operator.
  * @param {function(object): *} params.key - Unique key field for each tuple.
  * @param {function(object): *} params.parentKey - Field with key for parent tuple.
  */
export default function Stratify(params) {
  Transform.call(this, null, params);
}

Stratify.Definition = {
  "type": "Stratify",
  "metadata": {"treesource": true},
  "params": [
    { "name": "key", "type": "field", "required": true },
    { "name": "parentKey", "type": "field", "required": true  }
  ]
};

var prototype = inherits(Stratify, Transform);

prototype.transform = function(_, pulse) {
  if (!pulse.source) {
    error('Stratify transform requires an upstream data source.');
  }

  var mod = _.modified(), tree, map,
      out = pulse.fork(pulse.ALL).materialize(pulse.SOURCE),
      run = !this.value
         || mod
         || pulse.changed(pulse.ADD_REM)
         || pulse.modified(_.key.fields)
         || pulse.modified(_.parentKey.fields);

  // prevent upstream source pollution
  out.source = out.source.slice();

  if (run) {
    tree = stratify().id(_.key).parentId(_.parentKey)(out.source);
    map = tree.lookup = {};
    tree.each(function(node) { map[_.key(node.data)] = node; });
    this.value = tree;
  }

  out.source.root = this.value;
  return out;
};
<|endoftext|>


<commit_before>#!/usr/bin/env node
/*jshint esversion:6, node:true*/
'use strict';

const assert = require('assert-is');
const Socket = require('net').Socket;
const encrypt = require('../lib/utils').encrypt;
const Commands = require('../lib/utils').COMMANDS;
const parseCommand = require('../lib/utils').parseCommand;
const debug = require('debug')('poke-repl client');

var PSIGNALS = ['exit', 'error', 'unhandledException', 'SIGINT'];

var ERRORS = {
    SERVER_ERROR: 'poke-repl server error.',
    MISSING_CONFIG: 'poke-repl expects a "config" argument.',
    MISSING_HOST: 'poke-repl expects a "host" argument.',
    MISSING_PORT: 'poke-repl expets a "port" argument.',
    MISSING_PASS: 'poke-repl auth expects a "pass" argument.',
    MISSING_USER: 'poke-repl auth expects a "user" argument.'
}

module.exports = function $client(config){

    assert.isObject(config, ERRORS.MISSING_CONFIG);
    assert.isString(config.host, ERRORS.MISSING_HOST);
    assert.isDefined(config.port, ERRORS.MISSING_PORT);

    console.log('- Connecting to %s %s', config.host, config.port);

    var socket = new Socket();
    socket.on('close', closeConnection.bind(null, 'socket:close'));
    socket.on('error', closeConnection.bind(null, 'socket:error'));

    socket.on('data', handshakeHanlder);

    PSIGNALS.map((signal) =>{
        process.on(signal, closeConnection.bind(null, signal));
    });

    socket.connect(parseInt(config.port), config.host);

    /**
     * Handles the handshake with the server.
     *
     * It parses all commands, handles auth,
     * and then starts communication.
     *
     * 	@param  {Buffer} data
     */
    function handshakeHanlder(data){

        var command = parseCommand(data);

        switch(command.label){
            /*
             * The connection requires AUTH.
             * We are sent
             *
             */
            case Commands.AUTHORIZE:
                var seed = command.getSeed();

                if(!seed) {
                    return closeConnection(ERRORS.SERVER_ERROR);
                }

                assert.isString(config.user, closeConnection.bind(null, ERRORS.MISSING_USER));
                assert.isString(config.pass, closeConnection.bind(null, ERRORS.MISSING_PASS));

                var command = encrypt(config.user + ' ' + config.pass, seed);
                socket.write(command);
                break;

            case Commands.CONNECT:
                socket.removeListener('data', handshakeHanlder);
                handleConnection(socket);
                break;

            case Commands.EXIT:
                var label = command.getErrorMessage(config.verbose);
                closeConnection(label);
                break;

            default:
                console.log('--------------');
                console.log('Command not recognized');
                console.log('CMD: %s.', command.cmd);
                console.log('Original command: %s', data.toString());
                console.log('--------------');
        }
    };

    function handleConnection(socket){
        if(handleConnection.piping) return;
        handleConnection.piping = true;

        process.stdin.pipe(socket);
        process.stdin.setRawMode(true);

        socket.pipe(process.stdout);

        process.stdin.on('end', () => socket.destroy());

        process.stdin.on('data', (b) => {
            if(b.length === 1 && b[0] === 4){
                process.stdin.setRawMode(false);
                process.stdin.emit('end');
            }
        });
    }

    function closeConnection(label, e){
        console.log('closeConnection', label, e);
        if(closeConnection.called) return;
        closeConnection.called = true;

        console.log('HANDLE EXIT CALL: %s label', label);

        if(e){
            console.log(e);

            if(e.message){
                console.error(e.message);
            }

            if(e.stack){
                console.error(e.stack);
            }
        }

        try {
            process.stdin.setRawMode(false);
        } catch(e){
            console.error('ERROR', e.message);
        }

        socket.removeListener('close', closeConnection);
        socket.destroy();
        process.exit();
    }
};
<commit_msg>fix unused debug import<commit_after>#!/usr/bin/env node
/*jshint esversion:6, node:true*/
'use strict';

const assert = require('assert-is');
const Socket = require('net').Socket;
const encrypt = require('../lib/utils').encrypt;
const Commands = require('../lib/utils').COMMANDS;
const parseCommand = require('../lib/utils').parseCommand;
// const debug = require('debug')('poke-repl client');

var PSIGNALS = ['exit', 'error', 'unhandledException', 'SIGINT'];

var ERRORS = {
    SERVER_ERROR: 'poke-repl server error.',
    MISSING_CONFIG: 'poke-repl expects a "config" argument.',
    MISSING_HOST: 'poke-repl expects a "host" argument.',
    MISSING_PORT: 'poke-repl expets a "port" argument.',
    MISSING_PASS: 'poke-repl auth expects a "pass" argument.',
    MISSING_USER: 'poke-repl auth expects a "user" argument.'
}

module.exports = function $client(config){

    assert.isObject(config, ERRORS.MISSING_CONFIG);
    assert.isString(config.host, ERRORS.MISSING_HOST);
    assert.isDefined(config.port, ERRORS.MISSING_PORT);

    console.log('- Connecting to %s %s', config.host, config.port);

    var socket = new Socket();
    socket.on('close', closeConnection.bind(null, 'socket:close'));
    socket.on('error', closeConnection.bind(null, 'socket:error'));

    socket.on('data', handshakeHanlder);

    PSIGNALS.map((signal) =>{
        process.on(signal, closeConnection.bind(null, signal));
    });

    socket.connect(parseInt(config.port), config.host);

    /**
     * Handles the handshake with the server.
     *
     * It parses all commands, handles auth,
     * and then starts communication.
     *
     * 	@param  {Buffer} data
     */
    function handshakeHanlder(data){

        var command = parseCommand(data);

        switch(command.label){
            /*
             * The connection requires AUTH.
             * We are sent
             *
             */
            case Commands.AUTHORIZE:
                var seed = command.getSeed();

                if(!seed) {
                    return closeConnection(ERRORS.SERVER_ERROR);
                }

                assert.isString(config.user, closeConnection.bind(null, ERRORS.MISSING_USER));
                assert.isString(config.pass, closeConnection.bind(null, ERRORS.MISSING_PASS));

                var command = encrypt(config.user + ' ' + config.pass, seed);
                socket.write(command);
                break;

            case Commands.CONNECT:
                socket.removeListener('data', handshakeHanlder);
                handleConnection(socket);
                break;

            case Commands.EXIT:
                var label = command.getErrorMessage(config.verbose);
                closeConnection(label);
                break;

            default:
                console.log('--------------');
                console.log('Command not recognized');
                console.log('CMD: %s.', command.cmd);
                console.log('Original command: %s', data.toString());
                console.log('--------------');
        }
    };

    function handleConnection(socket){
        if(handleConnection.piping) return;
        handleConnection.piping = true;

        process.stdin.pipe(socket);
        process.stdin.setRawMode(true);

        socket.pipe(process.stdout);

        process.stdin.on('end', () => socket.destroy());

        process.stdin.on('data', (b) => {
            if(b.length === 1 && b[0] === 4){
                process.stdin.setRawMode(false);
                process.stdin.emit('end');
            }
        });
    }

    function closeConnection(label, e){
        console.log('closeConnection', label, e);
        if(closeConnection.called) return;
        closeConnection.called = true;

        console.log('HANDLE EXIT CALL: %s label', label);

        if(e){
            console.log(e);

            if(e.message){
                console.error(e.message);
            }

            if(e.stack){
                console.error(e.stack);
            }
        }

        try {
            process.stdin.setRawMode(false);
        } catch(e){
            console.error('ERROR', e.message);
        }

        socket.removeListener('close', closeConnection);
        socket.destroy();
        process.exit();
    }
};
<|endoftext|>


<commit_before>// Copyright 2012, Mark Cavage

var dns = require('dns');
var EventEmitter = require('events').EventEmitter;
var net = require('net');
var util = require('util');

var assert = require('assert-plus');
var backoff = require('backoff');
var clone = require('clone');
var WError = require('verror').WError;

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

///--- Globals

var slice = Function.prototype.call.bind(Array.prototype.slice);
var sprintf = util.format;

/* JSSTYLED */
var IP_RE = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
var MAX_MSGID = Math.pow(2, 31) - 1;
var MSGID = 0;

///--- Errors

function ConnectionClosedError() {
        WError.call(this, 'the underlying connection has been closed');
}
util.inherits(ConnectionClosedError, WError);
ConnectionClosedError.prototype.name = 'ConnectionClosedError';

function ConnectionTimeoutError(time) {
        WError.call(this, 'failed to establish connection after %dms', time);
}
util.inherits(ConnectionTimeoutError, WError);
ConnectionTimeoutError.prototype.name = 'ConnectionTimeoutError';

function DNSError(err, host) {
        WError.call(this, err, host + ' could not be found in DNS');
}
util.inherits(DNSError, WError);
DNSError.prototype.name = 'DNSError';

function NoConnectionError() {
        WError.call(this, 'no connection');
}
util.inherits(NoConnectionError, WError);
NoConnectionError.prototype.name = 'NoConnectionError';

function UnsolicitedMessageError(message) {
        WError.call(this, 'unsolicited message');
        this.msg = message;
}
util.inherits(UnsolicitedMessageError, WError);

///--- Helpers

function cleanupListener(l) {
        l.removeAllListeners('close');
        l.removeAllListeners('data');
        l.removeAllListeners('drain');
        l.removeAllListeners('end');
        l.removeAllListeners('error');
        l.removeAllListeners('timeout');
}

function nextMessageId() {
        if (++MSGID >= MAX_MSGID)
                MSGID = 1;

        return (MSGID);
}

function shuffle(array) {
        var current;
        var tmp;
        var top = array.length;

        if (top) {
                while (--top) {
                        current = Math.floor(Math.random() * (top + 1));
                        tmp = array[current];
                        array[current] = array[top];
                        array[top] = tmp;
                }
        }

        return (array);
}

function createSocket(options, cb) {

        function _socket() {
                var c = net.connect(options);
                var to = options.connectTimeout || 0;
                c.setTimeout(to);

                c.once('connect', function onConnect() {
                        c.setTimeout(0);
                        c.removeAllListeners('error');
                        c.removeAllListeners('timeout');
                        cb(null, c);
                });

                c.once('error', function onError(err) {
                        c.removeAllListeners('connect');
                        c.removeAllListeners('timeout');
                        cb(err);
                });

                c.once('timeout', function onTimeout() {
                        c.removeAllListeners('connect');
                        c.removeAllListeners('error');
                        c.destroy();
                        cb(new ConnectionTimeoutError(to));
                });
        }

        if (IP_RE.test(options.host)) {
                _socket();
        } else if (options.host === 'localhost' || options.host === '::1') {
                options.host = '127.0.0.1';
                _socket();
        } else {
                dns.resolve4(options.host, function (err, addrs) {
                        if (err) {
                                cb(new DNSError(err, options.host));
                                return;
                        } else if (!addrs || addrs.length === 0) {
                                cb(new DNSError(options.host));
                                return;
                        }

                        options = clone(options);
                        options.host = shuffle(addrs).pop();
                        _socket();
                });
        }
}

function connect(client, options, callback) {
        assert.object(client, 'client');
        assert.object(options, 'options');
        assert.number(options.connectTimeout, 'options.connectTimeout');
        assert.string(options.host, 'options.host');
        assert.number(options.port, 'options.port');
        assert.object(options.retry, 'options.retry');
        assert.func(callback, 'callback');

        var retry = backoff.call(createSocket, options, callback);

        retry.setStrategy(new backoff.ExponentialStrategy({
                initialDelay: options.retry.minTimeout || 1000,
                maxDelay: options.retry.maxTimeout || Infinity
        }));

        var maxRetries = options.retry.retries;
        if (typeof (maxRetries) === 'number' && maxRetries !== Infinity) {
                retry.failAfter(maxRetries);
        } else {
                retry.failAfter(10);
        }

        retry.on('backoff', client.emit.bind(client, 'connectAttempt'));

        return (retry);
}

///--- API

function Client(options) {
        EventEmitter.call(this);

        var self = this;

        this.conn = null;
        this.reconnect = options.reconnect;
        this.requests = {};

        function onConnect(connectErr, conn) {
                if (connectErr)
                        return (self.emit('error', connectErr));

                if (!self.reconnect) {
                        conn.on('close', function (had_err) {
                                self.emit('close', had_err);
                                cleanupListener(conn);
                        });
                        conn.on('error', function (err) {
                                self.emit('error', err);
                        });
                } else {
                        conn.once('close', function (had_err) {
                                cleanupListener(conn);
                                self.conn = null;

                                // Clean up any pending requests with an error
                                var _keys = Object.keys(self.requests);
                                var _err = new ConnectionClosedError();
                                _keys.forEach(function (k) {
                                        var r = self.requests[k];
                                        r.emit('error', _err);
                                        cleanupListener(r);
                                        delete self.requests[k];
                                });

                                self.emit('close', had_err);
                                if (self.reconnect) {
                                        var num = (typeof (self.reconnect) ===
                                                   'number');
                                        setTimeout(connect.bind(null,
                                                                self,
                                                                options,
                                                                onConnect),
                                                   num ? self.reconnect : 1000);
                                }
                        });

                        conn.once('error', function (err) {
                                if (self.listeners('error').length > 0)
                                        self.emit('error', err);
                                // Otherwise NOOP - close will fire next
                        });
                }

                self.conn = conn;
                self.conn.setKeepAlive(true, 60000);

                self.messageDecoder = new protocol.MessageDecoder();
                self.messageEncoder = new protocol.MessageEncoder();

                self.conn.pipe(self.messageDecoder);
                self.messageEncoder.pipe(self.conn);
                self.messageDecoder.on('message', function onResponse(msg) {
                        if (!msg.data || !msg.data.m || !msg.data.d) {
                                self.emit('error',
                                          new Error('invalid message'));
                                return (undefined);

                        }
                        var args;
                        var err;
                        var req;

                        if ((req = self.requests[msg.msgid])) {
                                switch (msg.status) {

                                case protocol.STATUS.DATA:
                                        args = msg.data.d;
                                        args.unshift('message');
                                        req.emit.apply(req, args);
                                        break;

                                case protocol.STATUS.END:
                                        if (msg.data.d.length) {
                                                args = msg.data.d;
                                                args.unshift('message');
                                                req.emit.apply(req, args);
                                                process.nextTick(function () {
                                                        req.emit('end');
                                                        cleanupListener(req);
                                                });
                                        } else {
                                                req.emit('end');
                                                cleanupListener(req);
                                        }
                                        delete self.requests[msg.msgid];
                                        break;

                                default:
                                        err = new WError(msg.data.d.message);
                                        err.name = msg.data.d.name;
                                        err.stack = msg.data.d.stack;
                                        req.emit('error', err);
                                        delete self.requests[msg.msgid];
                                        cleanupListener(req);
                                        break;
                                }
                        } else {
                                self.emit('error',
                                          new UnsolicitedMessageError(msg));
                        }

                        return (undefined);
                });

                self.emit('connect');
                return (undefined);
        }

        connect(this, options, onConnect);
}
util.inherits(Client, EventEmitter);

Client.prototype.close = function close() {
        this.reconnect = false;
        if (this.conn)
                this.conn.end();
};

Client.prototype.rpc = function rpc(method) {
        assert.string(method, 'method');

        var req = new EventEmitter();
        if (!this.conn) {
                process.nextTick(function () {
                        req.emit('error', new NoConnectionError());
                });
                return (req);
        }

        var msgid = nextMessageId();
        var self = this;
        var encoder = new protocol.RpcEncoder({
                encoder: self.messageEncoder,
                msgid: msgid,
                method: method
        });

        encoder.encode.apply(encoder, slice(arguments, 1));

        this.requests[msgid] = req;

        return (req);
};

Client.prototype.setTimeout = function setTimeout(timeout) {
        assert.number(timeout, 'timeout');

        if (!this.conn)
                throw new NoConnectionError();

        this.conn.setTimeout(timeout);
};

Client.prototype.toString = function toString() {
        var c = this.conn;
        var str = sprintf('[object FastClient<remote=%s:%s>]',
                          c ? c.remoteAddress : 'no_host',
                          c ? c.remotePort : 'no_port');

        return (str);
};

///--- Exports

module.exports = {
        createClient: function createClient(options) {
                var opts = clone(options);
                opts.connectTimeout = opts.connectTimeout || 1000;
                opts.host = opts.host || '127.0.0.1';
                if (opts.reconnect === undefined)
                        opts.reconnect = 1000;

                opts.retry = opts.retry || {
                        retries: 3
                };
                return (new Client(opts));
        }
};
<commit_msg>Skip WError client side<commit_after>// Copyright 2012, Mark Cavage

var dns = require('dns');
var EventEmitter = require('events').EventEmitter;
var net = require('net');
var util = require('util');

var assert = require('assert-plus');
var backoff = require('backoff');
var clone = require('clone');
var WError = require('verror').WError;

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

///--- Globals

var slice = Function.prototype.call.bind(Array.prototype.slice);
var sprintf = util.format;

/* JSSTYLED */
var IP_RE = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
var MAX_MSGID = Math.pow(2, 31) - 1;
var MSGID = 0;

///--- Errors

function ConnectionClosedError() {
        WError.call(this, 'the underlying connection has been closed');
}
util.inherits(ConnectionClosedError, WError);
ConnectionClosedError.prototype.name = 'ConnectionClosedError';

function ConnectionTimeoutError(time) {
        WError.call(this, 'failed to establish connection after %dms', time);
}
util.inherits(ConnectionTimeoutError, WError);
ConnectionTimeoutError.prototype.name = 'ConnectionTimeoutError';

function DNSError(err, host) {
        WError.call(this, err, host + ' could not be found in DNS');
}
util.inherits(DNSError, WError);
DNSError.prototype.name = 'DNSError';

function NoConnectionError() {
        WError.call(this, 'no connection');
}
util.inherits(NoConnectionError, WError);
NoConnectionError.prototype.name = 'NoConnectionError';

function UnsolicitedMessageError(message) {
        WError.call(this, 'unsolicited message');
        this.msg = message;
}
util.inherits(UnsolicitedMessageError, WError);

///--- Helpers

function cleanupListener(l) {
        l.removeAllListeners('close');
        l.removeAllListeners('data');
        l.removeAllListeners('drain');
        l.removeAllListeners('end');
        l.removeAllListeners('error');
        l.removeAllListeners('timeout');
}

function nextMessageId() {
        if (++MSGID >= MAX_MSGID)
                MSGID = 1;

        return (MSGID);
}

function shuffle(array) {
        var current;
        var tmp;
        var top = array.length;

        if (top) {
                while (--top) {
                        current = Math.floor(Math.random() * (top + 1));
                        tmp = array[current];
                        array[current] = array[top];
                        array[top] = tmp;
                }
        }

        return (array);
}

function createSocket(options, cb) {

        function _socket() {
                var c = net.connect(options);
                var to = options.connectTimeout || 0;
                c.setTimeout(to);

                c.once('connect', function onConnect() {
                        c.setTimeout(0);
                        c.removeAllListeners('error');
                        c.removeAllListeners('timeout');
                        cb(null, c);
                });

                c.once('error', function onError(err) {
                        c.removeAllListeners('connect');
                        c.removeAllListeners('timeout');
                        cb(err);
                });

                c.once('timeout', function onTimeout() {
                        c.removeAllListeners('connect');
                        c.removeAllListeners('error');
                        c.destroy();
                        cb(new ConnectionTimeoutError(to));
                });
        }

        if (IP_RE.test(options.host)) {
                _socket();
        } else if (options.host === 'localhost' || options.host === '::1') {
                options.host = '127.0.0.1';
                _socket();
        } else {
                dns.resolve4(options.host, function (err, addrs) {
                        if (err) {
                                cb(new DNSError(err, options.host));
                                return;
                        } else if (!addrs || addrs.length === 0) {
                                cb(new DNSError(options.host));
                                return;
                        }

                        options = clone(options);
                        options.host = shuffle(addrs).pop();
                        _socket();
                });
        }
}

function connect(client, options, callback) {
        assert.object(client, 'client');
        assert.object(options, 'options');
        assert.number(options.connectTimeout, 'options.connectTimeout');
        assert.string(options.host, 'options.host');
        assert.number(options.port, 'options.port');
        assert.object(options.retry, 'options.retry');
        assert.func(callback, 'callback');

        var retry = backoff.call(createSocket, options, callback);

        retry.setStrategy(new backoff.ExponentialStrategy({
                initialDelay: options.retry.minTimeout || 1000,
                maxDelay: options.retry.maxTimeout || Infinity
        }));

        var maxRetries = options.retry.retries;
        if (typeof (maxRetries) === 'number' && maxRetries !== Infinity) {
                retry.failAfter(maxRetries);
        } else {
                retry.failAfter(10);
        }

        retry.on('backoff', client.emit.bind(client, 'connectAttempt'));

        return (retry);
}

///--- API

function Client(options) {
        EventEmitter.call(this);

        var self = this;

        this.conn = null;
        this.reconnect = options.reconnect;
        this.requests = {};

        function onConnect(connectErr, conn) {
                if (connectErr)
                        return (self.emit('error', connectErr));

                if (!self.reconnect) {
                        conn.on('close', function (had_err) {
                                self.emit('close', had_err);
                                cleanupListener(conn);
                        });
                        conn.on('error', function (err) {
                                self.emit('error', err);
                        });
                } else {
                        conn.once('close', function (had_err) {
                                cleanupListener(conn);
                                self.conn = null;

                                // Clean up any pending requests with an error
                                var _keys = Object.keys(self.requests);
                                var _err = new ConnectionClosedError();
                                _keys.forEach(function (k) {
                                        var r = self.requests[k];
                                        r.emit('error', _err);
                                        cleanupListener(r);
                                        delete self.requests[k];
                                });

                                self.emit('close', had_err);
                                if (self.reconnect) {
                                        var num = (typeof (self.reconnect) ===
                                                   'number');
                                        setTimeout(connect.bind(null,
                                                                self,
                                                                options,
                                                                onConnect),
                                                   num ? self.reconnect : 1000);
                                }
                        });

                        conn.once('error', function (err) {
                                if (self.listeners('error').length > 0)
                                        self.emit('error', err);
                                // Otherwise NOOP - close will fire next
                        });
                }

                self.conn = conn;
                self.conn.setKeepAlive(true, 60000);

                self.messageDecoder = new protocol.MessageDecoder();
                self.messageEncoder = new protocol.MessageEncoder();

                self.conn.pipe(self.messageDecoder);
                self.messageEncoder.pipe(self.conn);
                self.messageDecoder.on('message', function onResponse(msg) {
                        if (!msg.data || !msg.data.m || !msg.data.d) {
                                self.emit('error',
                                          new Error('invalid message'));
                                return (undefined);

                        }
                        var args;
                        var err;
                        var req;

                        if ((req = self.requests[msg.msgid])) {
                                switch (msg.status) {

                                case protocol.STATUS.DATA:
                                        args = msg.data.d;
                                        args.unshift('message');
                                        req.emit.apply(req, args);
                                        break;

                                case protocol.STATUS.END:
                                        if (msg.data.d.length) {
                                                args = msg.data.d;
                                                args.unshift('message');
                                                req.emit.apply(req, args);
                                                process.nextTick(function () {
                                                        req.emit('end');
                                                        cleanupListener(req);
                                                });
                                        } else {
                                                req.emit('end');
                                                cleanupListener(req);
                                        }
                                        delete self.requests[msg.msgid];
                                        break;

                                default:
                                        err = new Error(msg.data.d.message);
                                        err.name = msg.data.d.name;
                                        err.stack = msg.data.d.stack;
                                        req.emit('error', err);
                                        delete self.requests[msg.msgid];
                                        cleanupListener(req);
                                        break;
                                }
                        } else {
                                self.emit('error',
                                          new UnsolicitedMessageError(msg));
                        }

                        return (undefined);
                });

                self.emit('connect');
                return (undefined);
        }

        connect(this, options, onConnect);
}
util.inherits(Client, EventEmitter);

Client.prototype.close = function close() {
        this.reconnect = false;
        if (this.conn)
                this.conn.end();
};

Client.prototype.rpc = function rpc(method) {
        assert.string(method, 'method');

        var req = new EventEmitter();
        if (!this.conn) {
                process.nextTick(function () {
                        req.emit('error', new NoConnectionError());
                });
                return (req);
        }

        var msgid = nextMessageId();
        var self = this;
        var encoder = new protocol.RpcEncoder({
                encoder: self.messageEncoder,
                msgid: msgid,
                method: method
        });

        encoder.encode.apply(encoder, slice(arguments, 1));

        this.requests[msgid] = req;

        return (req);
};

Client.prototype.setTimeout = function setTimeout(timeout) {
        assert.number(timeout, 'timeout');

        if (!this.conn)
                throw new NoConnectionError();

        this.conn.setTimeout(timeout);
};

Client.prototype.toString = function toString() {
        var c = this.conn;
        var str = sprintf('[object FastClient<remote=%s:%s>]',
                          c ? c.remoteAddress : 'no_host',
                          c ? c.remotePort : 'no_port');

        return (str);
};

///--- Exports

module.exports = {
        createClient: function createClient(options) {
                var opts = clone(options);
                opts.connectTimeout = opts.connectTimeout || 1000;
                opts.host = opts.host || '127.0.0.1';
                if (opts.reconnect === undefined)
                        opts.reconnect = 1000;

                opts.retry = opts.retry || {
                        retries: 3
                };
                return (new Client(opts));
        }
};
<|endoftext|>