<commit_before>var Master
  , cluster
  , exec = require('child_process').exec
  , fs = require('fs')
  , utils = require('../utils')
  , watchFiles = require('../watch_files')
  , Log = require('../../deps/log');

if (!geddy.FD_HACK) {
  cluster = require('cluster');
}

var processModes = {
  KEEP_ALIVE: 'keepAlive'
, SHUTDOWN: 'shutdown'
, WATCH_FILES: 'watchFiles'
};

Master = function () {
  this.init();
};

Master.prototype = new (function () {

  var _readConfig = function (next) {
        var opts = this.opts
          , dir = process.cwd()
          , appBaseConfig
          , appEnvConfig;

        this.config = require('../base_config');
        this.config.environment = opts.environment || this.config.environment;

        // Base config for workers-count should be 1 in dev-mode
        // Cycle based on filesystem changes, not keep-alive
        if (this.config.environment == 'development') {
          this.config.workers = 1;
          this.processMode = processModes.WATCH_FILES;
        }

        // App configs
        appBaseConfig = require(dir + '/config/environment');
        appEnvConfig = require(dir + '/config/' + this.config.environment);

        // Start with a blank slate, mix everything in
        utils.mixin(this.config, appBaseConfig);
        utils.mixin(this.config, appEnvConfig);
        utils.mixin(this.config, opts);

        next();
      }

    , _initLogging = function (next) {
        var self = this
          , callback
          , levelsByType
          , stdoutLevel
          , types = ['stdout', 'stderr', 'access']
          , now = (new Date()).getTime()
          , loggly
          , dir = this.config.logDir
          , rotateAndInitByType;

        callback = function () {
        };

        // Recursive function for rotating and initializing each of the log-types.
        // Calls the passed-in callback when the entire process is done
        rotateAndInitByType = function () {
          var type = types.shift()
            , cmd
            , nextLog;
          // Grab the next logger-type, if any
          if (type) {
            // Rename the log file, ex.: mv logs/access.log logs/access.<TIMESTAMP>.log
            cmd = 'mv ' + dir + '/' + type + '.log ' + dir + '/' + type + '.' + now + '.log';
            // After the file is renmaed, create the new logger with the original filename
            // e.g., access.log
            nextLog = function () {
              self[type + 'Log'] = new Log(levelsByType[type], fs.createWriteStream(dir +
                  '/' + type + '.log'), true, loggly);
              // Go on to the next logger type until none are left
              rotateAndInitByType();
            };
            exec(cmd, nextLog);
          }
          // No logger-types left, continue on with the main init process
          else {
            self.stdoutLog.info('Server starting with config: ' +
                JSON.stringify(self.config, true, 2));
            next();
          }
        };

        // Set the logging level for stdout
        if (this.config.debug) {
          stdoutLevel = Log.DEBUG;
        }
        else if (this.config.logLevel) {
          stdoutLevel = Log[this.config.logLevel]();
        }
        else {
          stdoutLevel = Log.INFO; // Default to info
        }

        // Now that we have the desired level for stdout, set up log levels by key
        levelsByType = {
          access: 'access'
        , stderr: 'error'
        , stdout: stdoutLevel
        };

        // Create the log directory if it doesn't exist
        exec('mkdir -p ' + dir, function (err) {
          if (err) {
            throw err;
          }
        });

        // Kick the log-init process off
        rotateAndInitByType();
      }

    , _monitorProcesses = function (next) {
        var self = this
          , workers = this.workers
          , count = this.config.workers
          , now = (new Date()).getTime()
          , heartbeatWindow = this.config.heartbeatWindow
          , killWorker;

        workers.each(function (data) {
          var worker = data.worker;

          // Kill if process hasn't called back in a while
          if ((now - worker.heartbeatAt) > heartbeatWindow) {
            killWorker = true;
            self.stdoutLog.warning("No current heartbeat from " + worker.pid + ", killing process.");
          }

          // Kill, manual-restart from code-changes in dev-mode
          if (self.processMode == processModes.WATCH_FILES) {
            killWorker = true;
            self.stdoutLog.warning("Code changed, killing " + worker.pid + ", cycling ...");
          }

          if (killWorker) {
            self.kill(worker.pid);
          }

        });

        if (this.processMode != processModes.SHUTDOWN) {
          this.createWorkers();;
          // If called manually, not part of the normal polling loop
          if (this.processMode == processModes.KEEP_ALIVE) {
            setTimeout(function () {
              _monitorProcesses.call(self);
            }, 5000);
          }
        }

        // Initial async-chain invocation during startup
        if (typeof next == 'function') {
          next();
        }
      }

    , _watchFiles = function () {
        var self = this
          , dir = process.cwd()
          , callback = function (curr, prev) {
              if (curr.mtime.getTime() != prev.mtime.getTime()) {
                _monitorProcesses.call(self, {manualRotate: true});
              }
            };
        // Watch individual files so we can compare mtimes and restart
        // on code-changes
        watchFiles.watch(dir + '/config', callback);
        watchFiles.watch(dir + '/lib', callback);
        watchFiles.watch(dir + '/app/controllers', callback);
        watchFiles.watch(dir + '/app/models', callback);
        watchFiles.watch(dir + '/app/views', callback);
      };

  this.init = function () {
    this.opts = null;
    this.config = {};
    this.workers = new geddy.SortedCollection();
    this.processMode = processModes.KEEP_ALIVE;
  };

  this.start = function (options) {
    var self = this
      , items
      , chain;

    this.opts = options || {};

    items = [
      _readConfig
    , _initLogging
    , _monitorProcesses
    ];

    chain = new geddy.async.SimpleAsyncChain(items, this);
    chain.last = function () {
      if (self.config.environment == 'development') {
        _watchFiles.call(self);
      }
    };
    chain.run();
  };

  this.createWorkers = function () {
    var configCount = this.config.workers
      , currentCount = this.workers.count
      , needed = configCount - currentCount
      , msg;
    if (needed) {
      msg = 'Creating ' + needed + ' worker process';
      msg += needed > 1 ? 'es.' : '.';
      this.stdoutLog.info(msg);
      while (currentCount < configCount) {
        currentCount++;
        this.createWorker();
      }
    }
  };

  this.createWorker = function () {
    var w = cluster.fork()
      , data = new WorkerData(w);
    this.workers.addItem(w.pid.toString(), data);
  };

  this.sendMessage = function (id, message) {
  };

  this.receiveMessage = function (id, message) {
  };

  this.killWorker = function (pid) {
    try { process.kill(pid); }
    catch(e) {}

    this.workers.removeItem(pid.toString());
  };

})();

WorkerData = function (worker) {
  this.heartbeatAt = (new Date()).getTime();
  this.process = null;
  this.pid = null;
  this.worker = worker;
};

module.exports.Master = Master;
module.exports.WorkerData = WorkerData;
<commit_msg>Col width.<commit_after>var Master
  , cluster
  , exec = require('child_process').exec
  , fs = require('fs')
  , utils = require('../utils')
  , watchFiles = require('../watch_files')
  , Log = require('../../deps/log');

if (!geddy.FD_HACK) {
  cluster = require('cluster');
}

var processModes = {
  KEEP_ALIVE: 'keepAlive'
, SHUTDOWN: 'shutdown'
, WATCH_FILES: 'watchFiles'
};

Master = function () {
  this.init();
};

Master.prototype = new (function () {

  var _readConfig = function (next) {
        var opts = this.opts
          , dir = process.cwd()
          , appBaseConfig
          , appEnvConfig;

        this.config = require('../base_config');
        this.config.environment = opts.environment || this.config.environment;

        // Base config for workers-count should be 1 in dev-mode
        // Cycle based on filesystem changes, not keep-alive
        if (this.config.environment == 'development') {
          this.config.workers = 1;
          this.processMode = processModes.WATCH_FILES;
        }

        // App configs
        appBaseConfig = require(dir + '/config/environment');
        appEnvConfig = require(dir + '/config/' + this.config.environment);

        // Start with a blank slate, mix everything in
        utils.mixin(this.config, appBaseConfig);
        utils.mixin(this.config, appEnvConfig);
        utils.mixin(this.config, opts);

        next();
      }

    , _initLogging = function (next) {
        var self = this
          , callback
          , levelsByType
          , stdoutLevel
          , types = ['stdout', 'stderr', 'access']
          , now = (new Date()).getTime()
          , loggly
          , dir = this.config.logDir
          , rotateAndInitByType;

        callback = function () {
        };

        // Recursive function for rotating and initializing each of the log-types.
        // Calls the passed-in callback when the entire process is done
        rotateAndInitByType = function () {
          var type = types.shift()
            , cmd
            , nextLog;
          // Grab the next logger-type, if any
          if (type) {
            // Rename the log file, ex.: mv logs/access.log logs/access.<TIMESTAMP>.log
            cmd = 'mv ' + dir + '/' + type + '.log ' + dir + '/' + type + '.' + now + '.log';
            // After the file is renmaed, create the new logger with the original filename
            // e.g., access.log
            nextLog = function () {
              self[type + 'Log'] = new Log(levelsByType[type], fs.createWriteStream(dir +
                  '/' + type + '.log'), true, loggly);
              // Go on to the next logger type until none are left
              rotateAndInitByType();
            };
            exec(cmd, nextLog);
          }
          // No logger-types left, continue on with the main init process
          else {
            self.stdoutLog.info('Server starting with config: ' +
                JSON.stringify(self.config, true, 2));
            next();
          }
        };

        // Set the logging level for stdout
        if (this.config.debug) {
          stdoutLevel = Log.DEBUG;
        }
        else if (this.config.logLevel) {
          stdoutLevel = Log[this.config.logLevel]();
        }
        else {
          stdoutLevel = Log.INFO; // Default to info
        }

        // Now that we have the desired level for stdout, set up log levels by key
        levelsByType = {
          access: 'access'
        , stderr: 'error'
        , stdout: stdoutLevel
        };

        // Create the log directory if it doesn't exist
        exec('mkdir -p ' + dir, function (err) {
          if (err) {
            throw err;
          }
        });

        // Kick the log-init process off
        rotateAndInitByType();
      }

    , _monitorProcesses = function (next) {
        var self = this
          , workers = this.workers
          , count = this.config.workers
          , now = (new Date()).getTime()
          , heartbeatWindow = this.config.heartbeatWindow
          , killWorker;

        workers.each(function (data) {
          var worker = data.worker;

          // Kill if process hasn't called back in a while
          if ((now - worker.heartbeatAt) > heartbeatWindow) {
            killWorker = true;
            self.stdoutLog.warning("No current heartbeat from " +
                worker.pid + ", killing process.");
          }

          // Kill, manual-restart from code-changes in dev-mode
          if (self.processMode == processModes.WATCH_FILES) {
            killWorker = true;
            self.stdoutLog.warning("Code changed, killing " +
                worker.pid + ", cycling ...");
          }

          if (killWorker) {
            self.kill(worker.pid);
          }

        });

        if (this.processMode != processModes.SHUTDOWN) {
          this.createWorkers();;
          // If called manually, not part of the normal polling loop
          if (this.processMode == processModes.KEEP_ALIVE) {
            setTimeout(function () {
              _monitorProcesses.call(self);
            }, 5000);
          }
        }

        // Initial async-chain invocation during startup
        if (typeof next == 'function') {
          next();
        }
      }

    , _watchFiles = function () {
        var self = this
          , dir = process.cwd()
          , callback = function (curr, prev) {
              if (curr.mtime.getTime() != prev.mtime.getTime()) {
                _monitorProcesses.call(self, {manualRotate: true});
              }
            };
        // Watch individual files so we can compare mtimes and restart
        // on code-changes
        watchFiles.watch(dir + '/config', callback);
        watchFiles.watch(dir + '/lib', callback);
        watchFiles.watch(dir + '/app/controllers', callback);
        watchFiles.watch(dir + '/app/models', callback);
        watchFiles.watch(dir + '/app/views', callback);
      };

  this.init = function () {
    this.opts = null;
    this.config = {};
    this.workers = new geddy.SortedCollection();
    this.processMode = processModes.KEEP_ALIVE;
  };

  this.start = function (options) {
    var self = this
      , items
      , chain;

    this.opts = options || {};

    items = [
      _readConfig
    , _initLogging
    , _monitorProcesses
    ];

    chain = new geddy.async.SimpleAsyncChain(items, this);
    chain.last = function () {
      if (self.config.environment == 'development') {
        _watchFiles.call(self);
      }
    };
    chain.run();
  };

  this.createWorkers = function () {
    var configCount = this.config.workers
      , currentCount = this.workers.count
      , needed = configCount - currentCount
      , msg;
    if (needed) {
      msg = 'Creating ' + needed + ' worker process';
      msg += needed > 1 ? 'es.' : '.';
      this.stdoutLog.info(msg);
      while (currentCount < configCount) {
        currentCount++;
        this.createWorker();
      }
    }
  };

  this.createWorker = function () {
    var w = cluster.fork()
      , data = new WorkerData(w);
    this.workers.addItem(w.pid.toString(), data);
  };

  this.sendMessage = function (id, message) {
  };

  this.receiveMessage = function (id, message) {
  };

  this.killWorker = function (pid) {
    try { process.kill(pid); }
    catch(e) {}

    this.workers.removeItem(pid.toString());
  };

})();

WorkerData = function (worker) {
  this.heartbeatAt = (new Date()).getTime();
  this.process = null;
  this.pid = null;
  this.worker = worker;
};

module.exports.Master = Master;
module.exports.WorkerData = WorkerData;
<|endoftext|>


<commit_before>let shelljs = require('shelljs');
let proxy = require('../core/proxy');
const Ipc = require('../core/ipc');
const constants = require('../constants.json');

class Simulator {
  constructor(options) {
    this.blockchainConfig = options.blockchainConfig;
    this.logger = options.logger;
  }

  run(options) {
    let cmds = [];

    const testrpc = shelljs.which('testrpc');
    const ganache = shelljs.which('ganache-cli-embark');
    if (!testrpc && !ganache) {
      this.logger.warn(__('%s is not installed on your machine', 'Ganache CLI (TestRPC)'));
      this.logger.info(__('You can install it by running: %s', 'npm -g install ganache-cli'));
      process.exit();
    }

    let useProxy = this.blockchainConfig.proxy || false;
    let host = (options.host || this.blockchainConfig.rpcHost || 'localhost');
    let port = (options.port || this.blockchainConfig.rpcPort || 8545);

    cmds.push("-p " + (port + (useProxy ? constants.blockchain.servicePortOnProxy : 0)));
    if (!ganache) {
      cmds.push("-h " + host);
    }
    cmds.push("-a " + (options.numAccounts || 10));
    cmds.push("-e " + (options.defaultBalance || 100));
    cmds.push("-l " + (options.gasLimit || 8000000));

    // adding mnemonic only if it is defined in the blockchainConfig or options
    let simulatorMnemonic = this.blockchainConfig.simulatorMnemonic || options.simulatorMnemonic;
    if (simulatorMnemonic) {
      cmds.push("--mnemonic \"" + (simulatorMnemonic) +"\"");
    }

    // adding blocktime only if it is defined in the blockchainConfig or options
    let simulatorBlocktime = this.blockchainConfig.simulatorBlocktime || options.simulatorBlocktime;
    if (simulatorBlocktime) {
      cmds.push("-b \"" + (simulatorBlocktime) +"\"");
    }

    const programName = ganache ? 'ganache-cli' : 'testrpc';
    const program = ganache ? ganache : testrpc;
    console.log(`running: ${programName} ${cmds.join(' ')}`);
    shelljs.exec(`${program} ${cmds.join(' ')}`, {async : true});

    if(useProxy){
      let ipcObject = new Ipc({ipcRole: 'client'});
      proxy.serve(ipcObject, host, port, false);
    }

  }
}

module.exports = Simulator;
<commit_msg>Embark's own ganache-cli will always be found<commit_after>let shelljs = require('shelljs');
let proxy = require('../core/proxy');
const Ipc = require('../core/ipc');
const constants = require('../constants.json');

class Simulator {
  constructor(options) {
    this.blockchainConfig = options.blockchainConfig;
    this.logger = options.logger;
  }

  run(options) {
    let cmds = [];

    const testrpc = shelljs.which('testrpc');
    const ganache = shelljs.which('ganache-cli-embark');
    // if (!testrpc && !ganache) {
    //   this.logger.warn(__('%s is not installed on your machine', 'Ganache CLI (TestRPC)'));
    //   this.logger.info(__('You can install it by running: %s', 'npm -g install ganache-cli'));
    //   process.exit();
    // }

    let useProxy = this.blockchainConfig.proxy || false;
    let host = (options.host || this.blockchainConfig.rpcHost || 'localhost');
    let port = (options.port || this.blockchainConfig.rpcPort || 8545);

    cmds.push("-p " + (port + (useProxy ? constants.blockchain.servicePortOnProxy : 0)));
    if (!ganache) {
      cmds.push("-h " + host);
    }
    cmds.push("-a " + (options.numAccounts || 10));
    cmds.push("-e " + (options.defaultBalance || 100));
    cmds.push("-l " + (options.gasLimit || 8000000));

    // adding mnemonic only if it is defined in the blockchainConfig or options
    let simulatorMnemonic = this.blockchainConfig.simulatorMnemonic || options.simulatorMnemonic;
    if (simulatorMnemonic) {
      cmds.push("--mnemonic \"" + (simulatorMnemonic) +"\"");
    }

    // adding blocktime only if it is defined in the blockchainConfig or options
    let simulatorBlocktime = this.blockchainConfig.simulatorBlocktime || options.simulatorBlocktime;
    if (simulatorBlocktime) {
      cmds.push("-b \"" + (simulatorBlocktime) +"\"");
    }

    // const programName = ganache ? 'ganache-cli' : 'testrpc';
    // const program = ganache ? ganache : testrpc;
    const programName = 'ganache-cli';
    const program = ganache;
    console.log(`running: ${programName} ${cmds.join(' ')}`);
    shelljs.exec(`${program} ${cmds.join(' ')}`, {async : true});

    if(useProxy){
      let ipcObject = new Ipc({ipcRole: 'client'});
      proxy.serve(ipcObject, host, port, false);
    }

  }
}

module.exports = Simulator;
<|endoftext|>


<commit_before>const sidTpl = require('./player/sid');
const prgTpl = require('./player/prg');

const defaultHeaderField = 'unknown';

const headerNames = ['title', 'author', 'released'];

class CodeGenerator {
  constructor(document, options) {
    if (typeof(document) === 'undefined') {
      throw new TypeError('document is required');
    }

    this.document = document;
    this.options = options || {};
  }

  generate() {
    let initialStates = this.document.initialState;

    let data = {
      debug: this.options.debug,
      headers: this._buildHeaders(),
      initialStates: initialStates,
      sequences: this._buildSequences(),
      song: this._buildSongTables(initialStates)
    };

    return this._template(data);
  }

  _buildHeaders() {
    let headers = {};

    for (let dir in this.document.directives) {
      if (headerNames.includes(dir)) {
        let value = this.document.directives[dir].trim();
        if (value.length > 32) {
          console.warn(`Argument of header #${dir.name.toUpperCase()} is ` +
            `too long (max 32 characters)`);
        }
        headers[dir.name] = value.slice(0, 32);
      }
    }

    for (let name of headerNames) {
      if (!headers[name]) {
        headers[name] = defaultHeaderField;
      }
      headers[name] = this._padRight(headers[name], 32);
    }

    return headers;
  }

  _buildSongTables(initialStates) {
    let songs = [], states = [];

    // create tables
    for (let i = 0; i < 3; i++) {
      songs[i]  = [];
      states[i] = Object.assign(initialStates[i]);
    }

    for (let elem of this.document.commands) {
      for (let channel of elem.channels) {
        let i = this._channelNumFromName(channel);
        let state = states[i];

        for (let cmd of elem.sequence) {
          console.log(cmd);

          switch (cmd.type) {
            case 'note':
            case 'rest':
              for (let b of this._bytesFromNoteCommand(cmd, state)) {
                songs[i].push(b);
              }
              break;
            case 'set_tempo':
              state.tempo = cmd.value;
              break;
            case 'set_note_length': {
              let oldNF = state.noteLengthFrames;
              let oldQF = state.quantLengthFrames;

              state.noteLength = cmd.value;

              let newNF = state.noteLengthFrames;
              let newQF = state.quantLengthFrames;

              if (newNF !== oldNF) {
                songs[i].push('I_NLEN', newNF-1);
              }
              if (newQF !== oldQF) {
                songs[i].push('I_QLEN', newQF-1);
              }
              break;
            }
            case 'set_octave':
              songs[i].push('I_OCTAVE', cmd.value);
              break;
            case 'set_quantize': {
              let oldQF = state.quantLengthFrames;

              state.quantLength = cmd.value;

              let newQF = state.quantLengthFrames;

              if (newQF !== oldQF) {
                songs[i].push('I_QLEN', newQF-1);
              }
              break;
            }
            case 'set_quantize_frames': {
              state.quantLength = cmd.value;
              let noteFrames = state.noteLengthFrames;
              let frames = cmd.value <= noteFrames ? cmd.value : noteFrames;
              songs[i].push('I_QLEN', frames);
              break;
            }
            case 'inc_octave':
              songs[i].push('I_OCT_INC');
              break;
            case 'dec_octave':
              songs[i].push('I_OCT_DEC');
              break;
            default:
              console.error(`Command not implemented yet: ${cmd}`);
          }
        }
      }
    }

    for (let i = 0; i < 3; i++) {
      songs[i].push('I_EOF');
    }

    return songs;
  }

  _buildSequences() {
    // TODO
    return {};
  }

  _channelNumFromName(name) {
    let n;
    if (name === 'A') { n = 0; }
    if (name === 'B') { n = 1; }
    if (name === 'C') { n = 2; }
    return n;
  }

  _bytesFromNoteCommand(command, state) {
    let bytes = [];

    let inst;
    if (command.type === 'rest') {
      inst = 'I_NOTE_REST';
    } else {
      let note = command.note.toUpperCase();
      let accidental = command.accidental === '+' ? 'S' : '';
      inst = `I_NOTE_${note}${accidental}`;
    }

    // If note length differs from current default note length, append note
    // length and quantization length bytes
    if (command.length !== null && state.noteLength !== command.length) {
      // Create a modified state based on custom note length from command
      let modState = Object.assign(state, { noteLength: command.length });

      let noteLen = modState.noteLengthFrames;
      let noteQuant = modState.quantLengthFrames;

      inst = inst + '|WITH_LEN_FLAG|WITH_Q_FLAG';
      if (noteLen > 0xff) {
        inst += '|WORD_FLAG';
      }

      bytes.push(inst);

      bytes.push(noteLen & 0xff);
      if (noteLen > 0xff) {
        bytes.push(noteLen >> 8 & 0xff);
      }

      bytes.push(noteQuant & 0xff);
      if (noteQuant > 0xff) {
        bytes.push(noteQuant >> 8 & 0xff);
      }
    } else {
      bytes.push(inst);
    }

    /*
    // TODO process "dots"
    if (command.length) {
      res.noteLen = this._framesFrom(command.length, state.tempo);
      res.noteQuant = Math.round(res.noteLen * (state.quant / 8));
    } else {
      res.noteLen = state.noteFrames;
      res.noteQuant = state.quantFrames;
    }
    */

    return bytes;
  }

  _template(data) {
    if (this.options.player) {
      return prgTpl(data);
    } else {
      return sidTpl(data);
    }
  }

  _padRight(str, len, char) {
    return str + Array(len - str.length + 1).join(char || ' ');
  }
}

module.exports = CodeGenerator;
<commit_msg>Store state before last note command to optimize space<commit_after>const State = require('./state');
const sidTpl = require('./player/sid');
const prgTpl = require('./player/prg');
const debug = require('debug')('code_generator');

const defaultHeaderField = 'unknown';

const headerNames = ['title', 'author', 'released'];

class CodeGenerator {
  constructor(document, options) {
    if (typeof(document) === 'undefined') {
      throw new TypeError('document is required');
    }

    this.document = document;
    this.options = options || {};
  }

  generate() {
    let initialStates = this.document.initialState;

    let data = {
      debug: this.options.debug,
      headers: this._buildHeaders(),
      initialStates: initialStates,
      sequences: this._buildSequences(),
      song: this._buildSongTables(initialStates)
    };

    return this._template(data);
  }

  _buildHeaders() {
    let headers = {};

    for (let dir in this.document.directives) {
      if (headerNames.includes(dir)) {
        let value = this.document.directives[dir].trim();
        if (value.length > 32) {
          console.warn(`Argument of header #${dir.name.toUpperCase()} is ` +
            `too long (max 32 characters)`);
        }
        headers[dir.name] = value.slice(0, 32);
      }
    }

    for (let name of headerNames) {
      if (!headers[name]) {
        headers[name] = defaultHeaderField;
      }
      headers[name] = this._padRight(headers[name], 32);
    }

    return headers;
  }

  _buildSongTables(initialStates) {
    let songs = [], states = [], lastStates = [];

    // create tables
    for (let i = 0; i < 3; i++) {
      songs[i]  = [];
      states[i] = new State(initialStates[i]);
      // lastState stores the state before the last *note command*
      lastStates[i] = new State(states[i]);
    }

    debug(`initialStates: ${JSON.stringify(lastStates, null, 4)}`);

    for (let elem of this.document.commands) {
      for (let channel of elem.channels) {
        let i = this._channelNumFromName(channel);

        let state = states[i];
        let lastState = lastStates[i];

        for (let cmd of elem.sequence) {
          debug(`#${i} cmd: ${JSON.stringify(cmd)}`);

          switch (cmd.type) {
            case 'note':
            case 'rest': {
              // push commands to change from lastState to state
              let changes = {};
              for (let k in state) {
                if (state[k] !== lastState[k]) {
                  changes[k] = state[k];
                }
              }
              if (state.noteLengthFrames !== lastState.noteLengthFrames) {
                changes.noteLengthFrames = state.noteLengthFrames;
              }
              if (state.quantLengthFrames !== lastState.quantLengthFrames) {
                changes.quantLengthFrames = state.quantLengthFrames;
              }
              debug(`#${i} changes: ${JSON.stringify(changes, null, 4)}`);

              // update lastState
              lastState = lastStates[i] = new State(state);

              // push commands based on changes
              if (changes.noteLength || changes.noteLengthFrames) {
                songs[i].push('I_NLEN', state.noteLengthFrames - 1);
              }
              if (changes.quantLength || changes.quantLengthFrames) {
                songs[i].push('I_QLEN', state.quantLengthFrames - 1);
              }

              // append notes
              for (let b of this._bytesFromNoteCommand(cmd, state)) {
                songs[i].push(b);
              }

              break;
            }
            case 'set_tempo':
              state.tempo = cmd.value;
              break;
            case 'set_note_length': {
              state.noteLength = cmd.value;
              break;
            }
            case 'set_quantize': {
              state.quantLength = cmd.value;
              break;
            }
            case 'set_octave':
              songs[i].push('I_OCTAVE', cmd.value);
              break;
            case 'inc_octave':
              songs[i].push('I_OCT_INC');
              break;
            case 'dec_octave':
              songs[i].push('I_OCT_DEC');
              break;
            default:
              console.error(`Command not implemented yet: ${cmd}`);
          }
        }
      }
    }

    for (let i = 0; i < 3; i++) {
      songs[i].push('I_EOF');
    }

    return songs;
  }

  _buildSequences() {
    // TODO
    return {};
  }

  _channelNumFromName(name) {
    let n;
    if (name === 'A') { n = 0; }
    if (name === 'B') { n = 1; }
    if (name === 'C') { n = 2; }
    return n;
  }

  _bytesFromNoteCommand(command, state) {
    let bytes = [];

    let inst;
    if (command.type === 'rest') {
      inst = 'I_NOTE_REST';
    } else {
      let note = command.note.toUpperCase();
      let accidental = command.accidental === '+' ? 'S' : '';
      inst = `I_NOTE_${note}${accidental}`;
    }

    // If note length differs from current default note length, append note
    // length and quantization length bytes
    if (command.length !== null && state.noteLength !== command.length) {
      // Create a modified state based on custom note length from command
      let modState = Object.assign(state, { noteLength: command.length });

      let noteLen = modState.noteLengthFrames;
      let noteQuant = modState.quantLengthFrames;

      inst = inst + '|WITH_LEN_FLAG|WITH_Q_FLAG';
      if (noteLen > 0xff) {
        inst += '|WORD_FLAG';
      }

      bytes.push(inst);

      bytes.push(noteLen & 0xff);
      if (noteLen > 0xff) {
        bytes.push(noteLen >> 8 & 0xff);
      }

      bytes.push(noteQuant & 0xff);
      if (noteQuant > 0xff) {
        bytes.push(noteQuant >> 8 & 0xff);
      }
    } else {
      bytes.push(inst);
    }

    /*
    // TODO process "dots"
    if (command.length) {
      res.noteLen = this._framesFrom(command.length, state.tempo);
      res.noteQuant = Math.round(res.noteLen * (state.quant / 8));
    } else {
      res.noteLen = state.noteFrames;
      res.noteQuant = state.quantFrames;
    }
    */

    return bytes;
  }

  _template(data) {
    if (this.options.player) {
      return prgTpl(data);
    } else {
      return sidTpl(data);
    }
  }

  _padRight(str, len, char) {
    return str + Array(len - str.length + 1).join(char || ' ');
  }
}

module.exports = CodeGenerator;
<|endoftext|>


<commit_before>// the eslint "no-unused-expressions" rule is triggered by the `expect`
// assertions in the tests. So, in order to avoid problems with eslint, I'm
// disabling that rule in this file
//
/* eslint-disable no-unused-expressions */

import React from 'react';
import { shallow, mount } from 'enzyme';
import chai from 'chai';
import sinon from 'sinon';
import DateInput from './DateInput';

const expect = chai.expect;

/* *****************************************************************************
the onChange handler for the DateInput component
    should not be called on initialization
    should be called on edit when the value has changed
    should not be called on edit when the value has not changed
    should be called on blur when the value has changed
    should not be called on blur when the value has not changed
*/
describe('the onChange handler for the DateInput component', () => {

    // it('should not be called on initialization', () => {});

    // it('should be called on edit when the value has changed', () => {});

    // it('should not be called on edit when the value has not changed', () => {});

    // it('should be called on blur when the value has changed', () => {});

    // it('should not be called on blur when the value has not changed', () => {});

});

/* *****************************************************************************
the onValidation handler for the DateInput component
    should be called on initialization with required=true, value=valid
    should be called on initialization with required=true, value=invalid
    should be called on initialization with required=true, value=blank
    should be called on initialization with required=false, value=valid
    should be called on initialization with required=false, value=invalid
    should be called on initialization with required=false, value=blank
    should not be called after change without prior blur event
    should be called on blur event
    should be called after change following a previous blur event
    should be called with a custom message on blur event with validationMessage=something
*/
describe('the onValidation handler for the DateInput component', () => {

    const description = 'a component';
    const expectedMessage = `${description} is not a valid date`;

    it('should be called on initialization with required=true, value=valid', () => {
        const onValidation = sinon.spy();

        const required = true;
        const value = '6/24/2016';

        mount(<DateInput required={required} value={value} onValidation={onValidation} />);

        expect(onValidation.callCount).to.equal(1, 'callcount');
        expect(onValidation.args[0][0]).to.equal(false, 'args[0][0]');
        expect(onValidation.args[0][1]).to.equal(true, 'args[0][1]');
        expect(onValidation.args[0][2]).to.equal(null, 'args[0][2]');
    });

    it('should be called on initialization with required=true, value=invalid', () => {
        const onValidation = sinon.spy();

        const required = true;
        const value = 'not a date';

        mount(
            <DateInput
                description={description}
                required={required}
                value={value}
                onValidation={onValidation}
            />
        );

        expect(onValidation.callCount).to.equal(1, 'callcount');
        expect(onValidation.args[0][0]).to.equal(false, 'args[0][0]');
        expect(onValidation.args[0][1]).to.equal(false, 'args[0][1]');
        expect(onValidation.args[0][2]).to.equal(expectedMessage, 'args[0][2]');
    });

    it('should be called on initialization with required=true, value=blank', () => {
        const onValidation = sinon.spy();

        const required = true;
        const value = '';

        mount(
            <DateInput
                description={description}
                required={required}
                value={value}
                onValidation={onValidation}
            />
        );

        expect(onValidation.callCount).to.equal(1, 'callcount');
        expect(onValidation.args[0][0]).to.equal(false, 'args[0][0]');
        expect(onValidation.args[0][1]).to.equal(false, 'args[0][1]');
        expect(onValidation.args[0][2]).to.equal(expectedMessage, 'args[0][2]');
    });

    it('should be called on initialization with required=false, value=valid', () => {
        const onValidation = sinon.spy();

        const required = false;
        const value = '11/3/2014';

        mount(
            <DateInput
                description={description}
                required={required}
                value={value}
                onValidation={onValidation}
            />
        );

        expect(onValidation.callCount).to.equal(1, 'callcount');
        expect(onValidation.args[0][0]).to.equal(false, 'args[0][0]');
        expect(onValidation.args[0][1]).to.equal(true, 'args[0][1]');
        expect(onValidation.args[0][2]).to.equal(null, 'args[0][2]');
    });

    it('should be called on initialization with required=false, value=invalid', () => {
        const onValidation = sinon.spy();

        const required = false;
        const value = 'another non-date';

        mount(
            <DateInput
                description={description}
                required={required}
                value={value}
                onValidation={onValidation}
            />
        );

        expect(onValidation.callCount).to.equal(1, 'callcount');
        expect(onValidation.args[0][0]).to.equal(false, 'args[0][0]');
        expect(onValidation.args[0][1]).to.equal(false, 'args[0][1]');
        expect(onValidation.args[0][2]).to.equal(expectedMessage, 'args[0][2]');
    });

    it('should be called on initialization with required=false, value=blank', () => {
        const onValidation = sinon.spy();

        const required = false;
        const value = '';

        mount(
            <DateInput
                description={description}
                required={required}
                value={value}
                onValidation={onValidation}
            />
        );

        expect(onValidation.callCount).to.equal(1, 'callcount');
        expect(onValidation.args[0][0]).to.equal(false, 'args[0][0]');
        expect(onValidation.args[0][1]).to.equal(true, 'args[0][1]');
        expect(onValidation.args[0][2]).to.equal(null, 'args[0][2]');
    });

    it('should not be called after change without prior blur event', () => {
        const onValidation = sinon.spy();

        const required = true;
        const initialValue = '3/6/2016';
        const finalValue = '6/8/2019';

        const component = mount(
            <DateInput
                description={description}
                required={required}
                value={initialValue}
                onValidation={onValidation}
            />
        );

        expect(onValidation.callCount).to.equal(1, 'callcount');

        component.find('input').simulate('change', {
            target: { value: finalValue }
        });

        expect(onValidation.callCount).to.equal(1, 'callcount');
    });

    it('should be called on blur event', () => {
        const onValidation = sinon.spy();

        const required = true;
        const initialValue = '3/6/2016';
        const finalValue = '6/8/2019';

        const component = mount(
            <DateInput
                description={description}
                required={required}
                value={initialValue}
                onValidation={onValidation}
            />
        );

        expect(onValidation.callCount).to.equal(1, 'callcount');

        component.find('input').simulate('blur', {
            target: { value: finalValue }
        });

        expect(onValidation.callCount).to.equal(2, 'callcount');
        expect(onValidation.args[1][0]).to.equal(true, 'args[1][0]');
        expect(onValidation.args[1][1]).to.equal(true, 'args[1][1]');
        expect(onValidation.args[1][2]).to.equal(null, 'args[1][2]');
    });

    it('should be called after change following a previous blur event', () => {
        const onValidation = sinon.spy();

        const required = true;
        const initialValue = '3/6/2016';
        const secondValue = '2/27/2011';
        const finalValue = 'whoops!';

        const component = mount(
            <DateInput
                description={description}
                required={required}
                value={initialValue}
                onValidation={onValidation}
            />
        );

        expect(onValidation.callCount).to.equal(1, 'callcount 1');

        component.find('input').simulate('blur', {
            target: { value: secondValue }
        });

        expect(onValidation.callCount).to.equal(2, 'callcount 2');

        component.find('input').simulate('change', {
            target: { value: finalValue }
        });

        expect(onValidation.callCount).to.equal(3, 'callcount 3');
        expect(onValidation.args[2][0]).to.equal(true, 'args[2][0]');
        expect(onValidation.args[2][1]).to.equal(false, 'args[2][1]');
        expect(onValidation.args[2][2]).to.equal(expectedMessage, 'args[2][2]');
    });

    it('should be called with a custom message on blur event with ' +
        'validationMessage=something', () => {
        const onValidation = sinon.spy();

        const required = true;
        const validationMessage = 'this is my custom message';
        const initialValue = '3/6/2016';
        const secondValue = '2/27/2011';
        const finalValue = 'whoops!';

        const component = mount(
            <DateInput
                description={description}
                required={required}
                validationMessage={validationMessage}
                value={initialValue}
                onValidation={onValidation}
            />
        );

        expect(onValidation.callCount).to.equal(1, 'callcount 1');

        component.find('input').simulate('blur', {
            target: { value: secondValue }
        });

        expect(onValidation.callCount).to.equal(2, 'callcount 2');

        component.find('input').simulate('change', {
            target: { value: finalValue }
        });

        expect(onValidation.callCount).to.equal(3, 'callcount 3');
        expect(onValidation.args[2][0]).to.equal(true, 'args[2][0]');
        expect(onValidation.args[2][1]).to.equal(false, 'args[2][1]');
        expect(onValidation.args[2][2]).to.equal(validationMessage, 'args[2][2]');
    });

});

/* *****************************************************************************
the basic markup of the DateInput component
    should be a div.form-group
    should include an input[type="text"]
    should include an input.form-control
    should include a label with the appropriate text if a label is specified
    should include a placeholder if a placeholder is specified
    should include a label with the the required flag if a label is specified & required is set
    should not include a label with the the required flag if a label is
        specified & required is not set
    should not include a label with the the required flag if a label is not
        specified & required is set
    should have the readOnly property on the input when readOnly=true
    should not have the readOnly property on the input when readOnly=false
    should have the correct label widths when labelColumns is set
    should have the correct select widths when inputColumns is set
*/
describe('the basic markup of the DateInput component', () => {

    it('should be a div.form-group', () => {
        const component = shallow(<DateInput />);

        expect(component.is('div.form-group')).to.equal(true);
    });

    it('should include an input[type="text"]', () => {
        const component = shallow(<DateInput />);

        expect(component.find('input[type="text"]').length).to.equal(1);
    });

    it('should include an input.form-control', () => {
        const component = shallow(<DateInput />);

        expect(component.find('input.form-control').length).to.equal(1);
    });

    it('should include a label with the appropriate text if a label is specified', () => {
        const label = 'this is silly';

        const component = shallow(<DateInput label={label} />);

        expect(component.find('Label').length).to.equal(1);
        expect(component.find('Label').props().label).to.equal(label);
    });

    it('should include a placeholder if a placeholder is specified', () => {
        const placeholder = 'this is silly';

        const component = shallow(<DateInput placeholder={placeholder} />);

        expect(component.find('input').props().placeholder).to.equal(placeholder);
    });

    it('should include a label with the the required flag if a label is ' +
        'specified & required is set', () => {
        const required = true;
        const label = 'this is silly';

        const component = shallow(<DateInput required={required} label={label} />);

        expect(component.find('Label').length).to.equal(1);
        expect(component.find('Label').props().required).to.equal(required);

    });

    it('should not include a label with the the required flag if a label is ' +
        'specified & required is not set', () => {
        const required = false;
        const label = 'this is silly';

        const component = shallow(<DateInput required={required} label={label} />);

        expect(component.find('Label').length).to.equal(1);
        expect(component.find('Label').props().required).to.equal(required);
    });

    it('should not include a label with the the required flag if a label is ' +
        'not specified & required is set', () => {
        const required = true;

        const component = shallow(<DateInput required={required} />);

        expect(component.find('Label').length).to.equal(0);
    });

    it('should have the readOnly property on the input when readOnly=true', () => {
        const readOnly = true;

        const component = shallow(<DateInput readOnly={readOnly} />);

        expect(component.find('input').props().readOnly).to.equal(readOnly);
    });

    it('should not have the readOnly property on the input when readOnly=false', () => {
        const readOnly = false;

        const component = shallow(<DateInput readOnly={readOnly} />);

        expect(component.find('input').props().readOnly).to.equal(readOnly);
    });

    it('should have the correct label widths when labelColumns is set', () => {
        const label = 'my label';
        const columns = { xs: 10, md: 8 };
        const expectedClass = 'col-xs-10 col-md-8';

        const component = shallow(<DateInput label={label} labelColumns={columns} />);

        expect(component.find('Label').props().className).to.equal(expectedClass);
    });

    it('should have the correct select widths when inputColumns is set', () => {
        const label = 'my label';
        const columns = { xs: 10, md: 8 };
        const expectedClass = '.col-xs-10.col-md-8';

        const component = shallow(<DateInput label={label} inputColumns={columns} />);

        expect(component.find(`div${expectedClass} input`).length).to.equal(1);
    });

});
<commit_msg>added specs for onChange handler<commit_after>// the eslint "no-unused-expressions" rule is triggered by the `expect`
// assertions in the tests. So, in order to avoid problems with eslint, I'm
// disabling that rule in this file
//
/* eslint-disable no-unused-expressions */

import React from 'react';
import { shallow, mount } from 'enzyme';
import chai from 'chai';
import sinon from 'sinon';
import DateInput from './DateInput';

const expect = chai.expect;

/* *****************************************************************************
the onChange handler for the DateInput component
    should not be called on initialization
    should be called on edit when the value has changed
    should not be called on edit when the value has not changed
    should be called on blur when the value has changed
    should not be called on blur when the value has not changed
*/
describe('the onChange handler for the DateInput component', () => {

    const description = 'a component';
    const expectedMessage = `${description} is not a valid date`;

    it('should not be called on initialization', () => {
        const onChange = sinon.spy();

        const required = true;
        const value = '6/24/2016';

        mount(<DateInput required={required} value={value} onChange={onChange} />);

        expect(onChange.callCount).to.equal(0, 'callcount');
    });

    it('should be called on edit when the value has changed', () => {
        const onChange = sinon.spy();

        const required = true;
        const value = '6/24/2016';

        const newValue = '6/25/2016';

        const component = mount(<DateInput required={required} value={value} onChange={onChange} />);

        expect(onChange.callCount).to.equal(0, 'callcount');

        component.find('input').simulate('change', {
            target: { value: newValue }
        });

        expect(onChange.callCount).to.equal(1, 'callcount');
        expect(onChange.calledWith(newValue)).to.equal(true, 'called with');
    });

    it('should not be called on edit when the value has not changed', () => {
        const onChange = sinon.spy();

        const required = true;
        const value = '6/24/2016';

        const newValue = value;

        const component = mount(<DateInput required={required} value={value} onChange={onChange} />);

        expect(onChange.callCount).to.equal(0, 'callcount');

        component.find('input').simulate('change', {
            target: { value: newValue }
        });

        expect(onChange.callCount).to.equal(0, 'callcount');
    });

    it('should be called on blur when the value has changed', () => {
        const onChange = sinon.spy();

        const required = true;
        const value = '6/24/2016';

        const newValue = '6/25/2016';

        const component = mount(<DateInput required={required} value={value} onChange={onChange} />);

        expect(onChange.callCount).to.equal(0, 'callcount');

        component.find('input').simulate('blur', {
            target: { value: newValue }
        });

        expect(onChange.callCount).to.equal(1, 'callcount');
        expect(onChange.calledWith(newValue)).to.equal(true, 'called with');
    });

    it('should not be called on blur when the value has not changed', () => {
        const onChange = sinon.spy();

        const required = true;
        const value = '6/24/2016';

        const newValue = value;

        const component = mount(<DateInput required={required} value={value} onChange={onChange} />);

        expect(onChange.callCount).to.equal(0, 'callcount');

        component.find('input').simulate('blur', {
            target: { value: newValue }
        });

        expect(onChange.callCount).to.equal(0, 'callcount');
    });

});

/* *****************************************************************************
the onValidation handler for the DateInput component
    should be called on initialization with required=true, value=valid
    should be called on initialization with required=true, value=invalid
    should be called on initialization with required=true, value=blank
    should be called on initialization with required=false, value=valid
    should be called on initialization with required=false, value=invalid
    should be called on initialization with required=false, value=blank
    should not be called after change without prior blur event
    should be called on blur event
    should be called after change following a previous blur event
    should be called with a custom message on blur event with validationMessage=something
*/
describe('the onValidation handler for the DateInput component', () => {

    const description = 'a component';
    const expectedMessage = `${description} is not a valid date`;

    it('should be called on initialization with required=true, value=valid', () => {
        const onValidation = sinon.spy();

        const required = true;
        const value = '6/24/2016';

        mount(<DateInput required={required} value={value} onValidation={onValidation} />);

        expect(onValidation.callCount).to.equal(1, 'callcount');
        expect(onValidation.args[0][0]).to.equal(false, 'args[0][0]');
        expect(onValidation.args[0][1]).to.equal(true, 'args[0][1]');
        expect(onValidation.args[0][2]).to.equal(null, 'args[0][2]');
    });

    it('should be called on initialization with required=true, value=invalid', () => {
        const onValidation = sinon.spy();

        const required = true;
        const value = 'not a date';

        mount(
            <DateInput
                description={description}
                required={required}
                value={value}
                onValidation={onValidation}
            />
        );

        expect(onValidation.callCount).to.equal(1, 'callcount');
        expect(onValidation.args[0][0]).to.equal(false, 'args[0][0]');
        expect(onValidation.args[0][1]).to.equal(false, 'args[0][1]');
        expect(onValidation.args[0][2]).to.equal(expectedMessage, 'args[0][2]');
    });

    it('should be called on initialization with required=true, value=blank', () => {
        const onValidation = sinon.spy();

        const required = true;
        const value = '';

        mount(
            <DateInput
                description={description}
                required={required}
                value={value}
                onValidation={onValidation}
            />
        );

        expect(onValidation.callCount).to.equal(1, 'callcount');
        expect(onValidation.args[0][0]).to.equal(false, 'args[0][0]');
        expect(onValidation.args[0][1]).to.equal(false, 'args[0][1]');
        expect(onValidation.args[0][2]).to.equal(expectedMessage, 'args[0][2]');
    });

    it('should be called on initialization with required=false, value=valid', () => {
        const onValidation = sinon.spy();

        const required = false;
        const value = '11/3/2014';

        mount(
            <DateInput
                description={description}
                required={required}
                value={value}
                onValidation={onValidation}
            />
        );

        expect(onValidation.callCount).to.equal(1, 'callcount');
        expect(onValidation.args[0][0]).to.equal(false, 'args[0][0]');
        expect(onValidation.args[0][1]).to.equal(true, 'args[0][1]');
        expect(onValidation.args[0][2]).to.equal(null, 'args[0][2]');
    });

    it('should be called on initialization with required=false, value=invalid', () => {
        const onValidation = sinon.spy();

        const required = false;
        const value = 'another non-date';

        mount(
            <DateInput
                description={description}
                required={required}
                value={value}
                onValidation={onValidation}
            />
        );

        expect(onValidation.callCount).to.equal(1, 'callcount');
        expect(onValidation.args[0][0]).to.equal(false, 'args[0][0]');
        expect(onValidation.args[0][1]).to.equal(false, 'args[0][1]');
        expect(onValidation.args[0][2]).to.equal(expectedMessage, 'args[0][2]');
    });

    it('should be called on initialization with required=false, value=blank', () => {
        const onValidation = sinon.spy();

        const required = false;
        const value = '';

        mount(
            <DateInput
                description={description}
                required={required}
                value={value}
                onValidation={onValidation}
            />
        );

        expect(onValidation.callCount).to.equal(1, 'callcount');
        expect(onValidation.args[0][0]).to.equal(false, 'args[0][0]');
        expect(onValidation.args[0][1]).to.equal(true, 'args[0][1]');
        expect(onValidation.args[0][2]).to.equal(null, 'args[0][2]');
    });

    it('should not be called after change without prior blur event', () => {
        const onValidation = sinon.spy();

        const required = true;
        const initialValue = '3/6/2016';
        const finalValue = '6/8/2019';

        const component = mount(
            <DateInput
                description={description}
                required={required}
                value={initialValue}
                onValidation={onValidation}
            />
        );

        expect(onValidation.callCount).to.equal(1, 'callcount');

        component.find('input').simulate('change', {
            target: { value: finalValue }
        });

        expect(onValidation.callCount).to.equal(1, 'callcount');
    });

    it('should be called on blur event', () => {
        const onValidation = sinon.spy();

        const required = true;
        const initialValue = '3/6/2016';
        const finalValue = '6/8/2019';

        const component = mount(
            <DateInput
                description={description}
                required={required}
                value={initialValue}
                onValidation={onValidation}
            />
        );

        expect(onValidation.callCount).to.equal(1, 'callcount');

        component.find('input').simulate('blur', {
            target: { value: finalValue }
        });

        expect(onValidation.callCount).to.equal(2, 'callcount');
        expect(onValidation.args[1][0]).to.equal(true, 'args[1][0]');
        expect(onValidation.args[1][1]).to.equal(true, 'args[1][1]');
        expect(onValidation.args[1][2]).to.equal(null, 'args[1][2]');
    });

    it('should be called after change following a previous blur event', () => {
        const onValidation = sinon.spy();

        const required = true;
        const initialValue = '3/6/2016';
        const secondValue = '2/27/2011';
        const finalValue = 'whoops!';

        const component = mount(
            <DateInput
                description={description}
                required={required}
                value={initialValue}
                onValidation={onValidation}
            />
        );

        expect(onValidation.callCount).to.equal(1, 'callcount 1');

        component.find('input').simulate('blur', {
            target: { value: secondValue }
        });

        expect(onValidation.callCount).to.equal(2, 'callcount 2');

        component.find('input').simulate('change', {
            target: { value: finalValue }
        });

        expect(onValidation.callCount).to.equal(3, 'callcount 3');
        expect(onValidation.args[2][0]).to.equal(true, 'args[2][0]');
        expect(onValidation.args[2][1]).to.equal(false, 'args[2][1]');
        expect(onValidation.args[2][2]).to.equal(expectedMessage, 'args[2][2]');
    });

    it('should be called with a custom message on blur event with ' +
        'validationMessage=something', () => {
        const onValidation = sinon.spy();

        const required = true;
        const validationMessage = 'this is my custom message';
        const initialValue = '3/6/2016';
        const secondValue = '2/27/2011';
        const finalValue = 'whoops!';

        const component = mount(
            <DateInput
                description={description}
                required={required}
                validationMessage={validationMessage}
                value={initialValue}
                onValidation={onValidation}
            />
        );

        expect(onValidation.callCount).to.equal(1, 'callcount 1');

        component.find('input').simulate('blur', {
            target: { value: secondValue }
        });

        expect(onValidation.callCount).to.equal(2, 'callcount 2');

        component.find('input').simulate('change', {
            target: { value: finalValue }
        });

        expect(onValidation.callCount).to.equal(3, 'callcount 3');
        expect(onValidation.args[2][0]).to.equal(true, 'args[2][0]');
        expect(onValidation.args[2][1]).to.equal(false, 'args[2][1]');
        expect(onValidation.args[2][2]).to.equal(validationMessage, 'args[2][2]');
    });

});

/* *****************************************************************************
the basic markup of the DateInput component
    should be a div.form-group
    should include an input[type="text"]
    should include an input.form-control
    should include a label with the appropriate text if a label is specified
    should include a placeholder if a placeholder is specified
    should include a label with the the required flag if a label is specified & required is set
    should not include a label with the the required flag if a label is
        specified & required is not set
    should not include a label with the the required flag if a label is not
        specified & required is set
    should have the readOnly property on the input when readOnly=true
    should not have the readOnly property on the input when readOnly=false
    should have the correct label widths when labelColumns is set
    should have the correct select widths when inputColumns is set
*/
describe('the basic markup of the DateInput component', () => {

    it('should be a div.form-group', () => {
        const component = shallow(<DateInput />);

        expect(component.is('div.form-group')).to.equal(true);
    });

    it('should include an input[type="text"]', () => {
        const component = shallow(<DateInput />);

        expect(component.find('input[type="text"]').length).to.equal(1);
    });

    it('should include an input.form-control', () => {
        const component = shallow(<DateInput />);

        expect(component.find('input.form-control').length).to.equal(1);
    });

    it('should include a label with the appropriate text if a label is specified', () => {
        const label = 'this is silly';

        const component = shallow(<DateInput label={label} />);

        expect(component.find('Label').length).to.equal(1);
        expect(component.find('Label').props().label).to.equal(label);
    });

    it('should include a placeholder if a placeholder is specified', () => {
        const placeholder = 'this is silly';

        const component = shallow(<DateInput placeholder={placeholder} />);

        expect(component.find('input').props().placeholder).to.equal(placeholder);
    });

    it('should include a label with the the required flag if a label is ' +
        'specified & required is set', () => {
        const required = true;
        const label = 'this is silly';

        const component = shallow(<DateInput required={required} label={label} />);

        expect(component.find('Label').length).to.equal(1);
        expect(component.find('Label').props().required).to.equal(required);

    });

    it('should not include a label with the the required flag if a label is ' +
        'specified & required is not set', () => {
        const required = false;
        const label = 'this is silly';

        const component = shallow(<DateInput required={required} label={label} />);

        expect(component.find('Label').length).to.equal(1);
        expect(component.find('Label').props().required).to.equal(required);
    });

    it('should not include a label with the the required flag if a label is ' +
        'not specified & required is set', () => {
        const required = true;

        const component = shallow(<DateInput required={required} />);

        expect(component.find('Label').length).to.equal(0);
    });

    it('should have the readOnly property on the input when readOnly=true', () => {
        const readOnly = true;

        const component = shallow(<DateInput readOnly={readOnly} />);

        expect(component.find('input').props().readOnly).to.equal(readOnly);
    });

    it('should not have the readOnly property on the input when readOnly=false', () => {
        const readOnly = false;

        const component = shallow(<DateInput readOnly={readOnly} />);

        expect(component.find('input').props().readOnly).to.equal(readOnly);
    });

    it('should have the correct label widths when labelColumns is set', () => {
        const label = 'my label';
        const columns = { xs: 10, md: 8 };
        const expectedClass = 'col-xs-10 col-md-8';

        const component = shallow(<DateInput label={label} labelColumns={columns} />);

        expect(component.find('Label').props().className).to.equal(expectedClass);
    });

    it('should have the correct select widths when inputColumns is set', () => {
        const label = 'my label';
        const columns = { xs: 10, md: 8 };
        const expectedClass = '.col-xs-10.col-md-8';

        const component = shallow(<DateInput label={label} inputColumns={columns} />);

        expect(component.find(`div${expectedClass} input`).length).to.equal(1);
    });

});
<|endoftext|>


<commit_before>'use strict';

const process = require('process');
const Timers = require('timers');

const Readable = require('stream').Readable;

const Command = require('./command.js');
const Packets = require('../packets/index.js');
const getTextParser = require('../parsers/text_parser.js');
const ServerStatus = require('../constants/server_status.js');
const CharsetToEncoding = require('../constants/charset_encodings.js');

const EmptyPacket = new Packets.Packet(0, Buffer.allocUnsafe(4), 0, 4);

// http://dev.mysql.com/doc/internals/en/com-query.html
class Query extends Command {
  constructor(options, callback) {
    super();
    this.sql = options.sql;
    this.values = options.values;
    this._queryOptions = options;
    this.namedPlaceholders = options.namedPlaceholders || false;
    this.onResult = callback;
    this.timeout = options.timeout;
    this.queryTimeout = null;
    this._fieldCount = 0;
    this._rowParser = null;
    this._fields = [];
    this._rows = [];
    this._receivedFieldsCount = 0;
    this._resultIndex = 0;
    this._localStream = null;
    this._unpipeStream = function() {};
    this._streamFactory = options.infileStreamFactory;
    this._connection = null;
  }

  then() {
    const err =
      "You have tried to call .then(), .catch(), or invoked await on the result of query that is not a promise, which is a programming error. Try calling con.promise().query(), or require('mysql2/promise') instead of 'mysql2' for a promise-compatible version of the query interface. To learn how to use async/await or Promises check out documentation at https://www.npmjs.com/package/mysql2#using-promise-wrapper, or the mysql2 documentation at https://github.com/sidorares/node-mysql2/tree/master/documentation/Promise-Wrapper.md";
    // eslint-disable-next-line
    console.log(err);
    throw new Error(err);
  }

  start(packet, connection) {
    if (connection.config.debug) {
      // eslint-disable-next-line
      console.log('        Sending query command: %s', this.sql);
    }
    this._connection = connection;
    this.options = Object.assign({}, connection.config, this._queryOptions);
    this._setTimeout();

    const cmdPacket = new Packets.Query(
      this.sql,
      connection.config.charsetNumber
    );
    connection.writePacket(cmdPacket.toPacket(1));
    return Query.prototype.resultsetHeader;
  }

  done() {
    this._unpipeStream();
    // if all ready timeout, return null directly
    if (this.timeout && !this.queryTimeout) {
      return null;
    }
    // else clear timer
    if (this.queryTimeout) {
      Timers.clearTimeout(this.queryTimeout);
      this.queryTimeout = null;
    }
    if (this.onResult) {
      let rows, fields;
      if (this._resultIndex === 0) {
        rows = this._rows[0];
        fields = this._fields[0];
      } else {
        rows = this._rows;
        fields = this._fields;
      }
      if (fields) {
        process.nextTick(() => {
          this.onResult(null, rows, fields);
        });
      } else {
        process.nextTick(() => {
          this.onResult(null, rows);
        });
      }
    }
    return null;
  }

  doneInsert(rs) {
    if (this._localStreamError) {
      if (this.onResult) {
        this.onResult(this._localStreamError, rs);
      } else {
        this.emit('error', this._localStreamError);
      }
      return null;
    }
    this._rows.push(rs);
    this._fields.push(void 0);
    this.emit('fields', void 0);
    this.emit('result', rs);
    if (rs.serverStatus & ServerStatus.SERVER_MORE_RESULTS_EXISTS) {
      this._resultIndex++;
      return this.resultsetHeader;
    }
    return this.done();
  }

  resultsetHeader(packet, connection) {
    const rs = new Packets.ResultSetHeader(packet, connection);
    this._fieldCount = rs.fieldCount;
    if (connection.config.debug) {
      // eslint-disable-next-line
      console.log(
        `        Resultset header received, expecting ${rs.fieldCount} column definition packets`
      );
    }
    if (this._fieldCount === 0) {
      return this.doneInsert(rs);
    }
    if (this._fieldCount === null) {
      return this._streamLocalInfile(connection, rs.infileName);
    }
    this._receivedFieldsCount = 0;
    this._rows.push([]);
    this._fields.push([]);
    return this.readField;
  }

  _streamLocalInfile(connection, path) {
    if (this._streamFactory) {
      this._localStream = this._streamFactory(path);
    } else {
      this._localStreamError = new Error(
        `As a result of LOCAL INFILE command server wants to read ${path} file, but as of v2.0 you must provide streamFactory option returning ReadStream.`
      );
      connection.writePacket(EmptyPacket);
      return this.infileOk;
    }

    const onConnectionError = () => {
      this._unpipeStream();
    };
    const onDrain = () => {
      this._localStream.resume();
    };
    const onPause = () => {
      this._localStream.pause();
    };
    const onData = function(data) {
      const dataWithHeader = Buffer.allocUnsafe(data.length + 4);
      data.copy(dataWithHeader, 4);
      connection.writePacket(
        new Packets.Packet(0, dataWithHeader, 0, dataWithHeader.length)
      );
    };
    const onEnd = () => {
      connection.removeListener('error', onConnectionError);
      connection.writePacket(EmptyPacket);
    };
    const onError = err => {
      this._localStreamError = err;
      connection.removeListener('error', onConnectionError);
      connection.writePacket(EmptyPacket);
    };
    this._unpipeStream = () => {
      connection.stream.removeListener('pause', onPause);
      connection.stream.removeListener('drain', onDrain);
      this._localStream.removeListener('data', onData);
      this._localStream.removeListener('end', onEnd);
      this._localStream.removeListener('error', onError);
    };
    connection.stream.on('pause', onPause);
    connection.stream.on('drain', onDrain);
    this._localStream.on('data', onData);
    this._localStream.on('end', onEnd);
    this._localStream.on('error', onError);
    connection.once('error', onConnectionError);
    return this.infileOk;
  }

  readField(packet, connection) {
    this._receivedFieldsCount++;
    // Often there is much more data in the column definition than in the row itself
    // If you set manually _fields[0] to array of ColumnDefinition's (from previous call)
    // you can 'cache' result of parsing. Field packets still received, but ignored in that case
    // this is the reason _receivedFieldsCount exist (otherwise we could just use current length of fields array)
    if (this._fields[this._resultIndex].length !== this._fieldCount) {
      const field = new Packets.ColumnDefinition(
        packet,
        connection.clientEncoding
      );
      this._fields[this._resultIndex].push(field);
      if (connection.config.debug) {
        /* eslint-disable no-console */
        console.log('        Column definition:');
        console.log(`          name: ${field.name}`);
        console.log(`          type: ${field.columnType}`);
        console.log(`         flags: ${field.flags}`);
        /* eslint-enable no-console */
      }
    }
    // last field received
    if (this._receivedFieldsCount === this._fieldCount) {
      const fields = this._fields[this._resultIndex];
      this.emit('fields', fields);
      this._rowParser = getTextParser(fields, this.options, connection.config);
      return Query.prototype.fieldsEOF;
    }
    return Query.prototype.readField;
  }

  fieldsEOF(packet, connection) {
    // check EOF
    if (!packet.isEOF()) {
      return connection.protocolError('Expected EOF packet');
    }
    return this.row;
  }

  row(packet) {
    if (packet.isEOF()) {
      const status = packet.eofStatusFlags();
      const moreResults = status & ServerStatus.SERVER_MORE_RESULTS_EXISTS;
      if (moreResults) {
        this._resultIndex++;
        return Query.prototype.resultsetHeader;
      }
      return this.done();
    }
    let row;
    try {
      row = new this._rowParser(
        packet,
        this._fields[this._resultIndex],
        this.options,
        CharsetToEncoding
      );
    } catch (err) {
      this._localStreamError = err;
      return this.doneInsert(null);
    }
    if (this.onResult) {
      this._rows[this._resultIndex].push(row);
    } else {
      this.emit('result', row);
    }
    return Query.prototype.row;
  }

  infileOk(packet, connection) {
    const rs = new Packets.ResultSetHeader(packet, connection);
    return this.doneInsert(rs);
  }

  stream(options) {
    options = options || {};
    options.objectMode = true;
    const stream = new Readable(options);
    stream._read = () => {
      this._connection && this._connection.resume();
    };
    this.on('result', row => {
      if (!stream.push(row)) {
        this._connection.pause();
      }
      stream.emit('result', row); // replicate old emitter
    });
    this.on('error', err => {
      stream.emit('error', err); // Pass on any errors
    });
    this.on('end', () => {
      stream.push(null); // pushing null, indicating EOF
      stream.emit('close'); // notify readers that query has completed
    });
    this.on('fields', fields => {
      stream.emit('fields', fields); // replicate old emitter
    });
    return stream;
  }

  _setTimeout() {
    if (this.timeout) {
      const timeoutHandler = this._handleTimeoutError.bind(this);
      this.queryTimeout = Timers.setTimeout(
        timeoutHandler,
        this.timeout
      );
    }
  }

  _handleTimeoutError() {
    if (this.queryTimeout) {
      Timers.clearTimeout(this.queryTimeout);
      this.queryTimeout = null;
    }

    const err = new Error('Query inactivity timeout');
    err.errorno = 'PROTOCOL_SEQUENCE_TIMEOUT';
    err.code = 'PROTOCOL_SEQUENCE_TIMEOUT';
    err.syscall = 'query';

    if (this.onResult) {
      this.onResult(err);
    } else {
      this.emit('error', err);
    }
  }
}

Query.prototype.catch = Query.prototype.then;

module.exports = Query;
<commit_msg>Optimize Query.row call<commit_after>'use strict';

const process = require('process');
const Timers = require('timers');

const Readable = require('stream').Readable;

const Command = require('./command.js');
const Packets = require('../packets/index.js');
const getTextParser = require('../parsers/text_parser.js');
const ServerStatus = require('../constants/server_status.js');
const CharsetToEncoding = require('../constants/charset_encodings.js');

const EmptyPacket = new Packets.Packet(0, Buffer.allocUnsafe(4), 0, 4);

// http://dev.mysql.com/doc/internals/en/com-query.html
class Query extends Command {
  constructor(options, callback) {
    super();
    this.sql = options.sql;
    this.values = options.values;
    this._queryOptions = options;
    this.namedPlaceholders = options.namedPlaceholders || false;
    this.onResult = callback;
    this.timeout = options.timeout;
    this.queryTimeout = null;
    this._fieldCount = 0;
    this._rowParser = null;
    this._fields = [];
    this._rows = [];
    this._receivedFieldsCount = 0;
    this._resultIndex = 0;
    this._localStream = null;
    this._unpipeStream = function() {};
    this._streamFactory = options.infileStreamFactory;
    this._connection = null;
  }

  then() {
    const err =
      "You have tried to call .then(), .catch(), or invoked await on the result of query that is not a promise, which is a programming error. Try calling con.promise().query(), or require('mysql2/promise') instead of 'mysql2' for a promise-compatible version of the query interface. To learn how to use async/await or Promises check out documentation at https://www.npmjs.com/package/mysql2#using-promise-wrapper, or the mysql2 documentation at https://github.com/sidorares/node-mysql2/tree/master/documentation/Promise-Wrapper.md";
    // eslint-disable-next-line
    console.log(err);
    throw new Error(err);
  }

  /* eslint no-unused-vars: ["error", { "argsIgnorePattern": "^_" }] */
  start(_packet, connection) {
    if (connection.config.debug) {
      // eslint-disable-next-line
      console.log('        Sending query command: %s', this.sql);
    }
    this._connection = connection;
    this.options = Object.assign({}, connection.config, this._queryOptions);
    this._setTimeout();

    const cmdPacket = new Packets.Query(
      this.sql,
      connection.config.charsetNumber
    );
    connection.writePacket(cmdPacket.toPacket(1));
    return Query.prototype.resultsetHeader;
  }

  done() {
    this._unpipeStream();
    // if all ready timeout, return null directly
    if (this.timeout && !this.queryTimeout) {
      return null;
    }
    // else clear timer
    if (this.queryTimeout) {
      Timers.clearTimeout(this.queryTimeout);
      this.queryTimeout = null;
    }
    if (this.onResult) {
      let rows, fields;
      if (this._resultIndex === 0) {
        rows = this._rows[0];
        fields = this._fields[0];
      } else {
        rows = this._rows;
        fields = this._fields;
      }
      if (fields) {
        process.nextTick(() => {
          this.onResult(null, rows, fields);
        });
      } else {
        process.nextTick(() => {
          this.onResult(null, rows);
        });
      }
    }
    return null;
  }

  doneInsert(rs) {
    if (this._localStreamError) {
      if (this.onResult) {
        this.onResult(this._localStreamError, rs);
      } else {
        this.emit('error', this._localStreamError);
      }
      return null;
    }
    this._rows.push(rs);
    this._fields.push(void 0);
    this.emit('fields', void 0);
    this.emit('result', rs);
    if (rs.serverStatus & ServerStatus.SERVER_MORE_RESULTS_EXISTS) {
      this._resultIndex++;
      return this.resultsetHeader;
    }
    return this.done();
  }

  resultsetHeader(packet, connection) {
    const rs = new Packets.ResultSetHeader(packet, connection);
    this._fieldCount = rs.fieldCount;
    if (connection.config.debug) {
      // eslint-disable-next-line
      console.log(
        `        Resultset header received, expecting ${rs.fieldCount} column definition packets`
      );
    }
    if (this._fieldCount === 0) {
      return this.doneInsert(rs);
    }
    if (this._fieldCount === null) {
      return this._streamLocalInfile(connection, rs.infileName);
    }
    this._receivedFieldsCount = 0;
    this._rows.push([]);
    this._fields.push([]);
    return this.readField;
  }

  _streamLocalInfile(connection, path) {
    if (this._streamFactory) {
      this._localStream = this._streamFactory(path);
    } else {
      this._localStreamError = new Error(
        `As a result of LOCAL INFILE command server wants to read ${path} file, but as of v2.0 you must provide streamFactory option returning ReadStream.`
      );
      connection.writePacket(EmptyPacket);
      return this.infileOk;
    }

    const onConnectionError = () => {
      this._unpipeStream();
    };
    const onDrain = () => {
      this._localStream.resume();
    };
    const onPause = () => {
      this._localStream.pause();
    };
    const onData = function(data) {
      const dataWithHeader = Buffer.allocUnsafe(data.length + 4);
      data.copy(dataWithHeader, 4);
      connection.writePacket(
        new Packets.Packet(0, dataWithHeader, 0, dataWithHeader.length)
      );
    };
    const onEnd = () => {
      connection.removeListener('error', onConnectionError);
      connection.writePacket(EmptyPacket);
    };
    const onError = err => {
      this._localStreamError = err;
      connection.removeListener('error', onConnectionError);
      connection.writePacket(EmptyPacket);
    };
    this._unpipeStream = () => {
      connection.stream.removeListener('pause', onPause);
      connection.stream.removeListener('drain', onDrain);
      this._localStream.removeListener('data', onData);
      this._localStream.removeListener('end', onEnd);
      this._localStream.removeListener('error', onError);
    };
    connection.stream.on('pause', onPause);
    connection.stream.on('drain', onDrain);
    this._localStream.on('data', onData);
    this._localStream.on('end', onEnd);
    this._localStream.on('error', onError);
    connection.once('error', onConnectionError);
    return this.infileOk;
  }

  readField(packet, connection) {
    this._receivedFieldsCount++;
    // Often there is much more data in the column definition than in the row itself
    // If you set manually _fields[0] to array of ColumnDefinition's (from previous call)
    // you can 'cache' result of parsing. Field packets still received, but ignored in that case
    // this is the reason _receivedFieldsCount exist (otherwise we could just use current length of fields array)
    if (this._fields[this._resultIndex].length !== this._fieldCount) {
      const field = new Packets.ColumnDefinition(
        packet,
        connection.clientEncoding
      );
      this._fields[this._resultIndex].push(field);
      if (connection.config.debug) {
        /* eslint-disable no-console */
        console.log('        Column definition:');
        console.log(`          name: ${field.name}`);
        console.log(`          type: ${field.columnType}`);
        console.log(`         flags: ${field.flags}`);
        /* eslint-enable no-console */
      }
    }
    // last field received
    if (this._receivedFieldsCount === this._fieldCount) {
      const fields = this._fields[this._resultIndex];
      this.emit('fields', fields);
      this._rowParser = getTextParser(fields, this.options, connection.config);
      return Query.prototype.fieldsEOF;
    }
    return Query.prototype.readField;
  }

  fieldsEOF(packet, connection) {
    // check EOF
    if (!packet.isEOF()) {
      return connection.protocolError('Expected EOF packet');
    }
    return this.row;
  }

  /* eslint no-unused-vars: ["error", { "argsIgnorePattern": "^_" }] */
  row(packet, _connection) {
    if (packet.isEOF()) {
      const status = packet.eofStatusFlags();
      const moreResults = status & ServerStatus.SERVER_MORE_RESULTS_EXISTS;
      if (moreResults) {
        this._resultIndex++;
        return Query.prototype.resultsetHeader;
      }
      return this.done();
    }
    let row;
    try {
      row = new this._rowParser(
        packet,
        this._fields[this._resultIndex],
        this.options,
        CharsetToEncoding
      );
    } catch (err) {
      this._localStreamError = err;
      return this.doneInsert(null);
    }
    if (this.onResult) {
      this._rows[this._resultIndex].push(row);
    } else {
      this.emit('result', row);
    }
    return Query.prototype.row;
  }

  infileOk(packet, connection) {
    const rs = new Packets.ResultSetHeader(packet, connection);
    return this.doneInsert(rs);
  }

  stream(options) {
    options = options || {};
    options.objectMode = true;
    const stream = new Readable(options);
    stream._read = () => {
      this._connection && this._connection.resume();
    };
    this.on('result', row => {
      if (!stream.push(row)) {
        this._connection.pause();
      }
      stream.emit('result', row); // replicate old emitter
    });
    this.on('error', err => {
      stream.emit('error', err); // Pass on any errors
    });
    this.on('end', () => {
      stream.push(null); // pushing null, indicating EOF
      stream.emit('close'); // notify readers that query has completed
    });
    this.on('fields', fields => {
      stream.emit('fields', fields); // replicate old emitter
    });
    return stream;
  }

  _setTimeout() {
    if (this.timeout) {
      const timeoutHandler = this._handleTimeoutError.bind(this);
      this.queryTimeout = Timers.setTimeout(
        timeoutHandler,
        this.timeout
      );
    }
  }

  _handleTimeoutError() {
    if (this.queryTimeout) {
      Timers.clearTimeout(this.queryTimeout);
      this.queryTimeout = null;
    }

    const err = new Error('Query inactivity timeout');
    err.errorno = 'PROTOCOL_SEQUENCE_TIMEOUT';
    err.code = 'PROTOCOL_SEQUENCE_TIMEOUT';
    err.syscall = 'query';

    if (this.onResult) {
      this.onResult(err);
    } else {
      this.emit('error', err);
    }
  }
}

Query.prototype.catch = Query.prototype.then;

module.exports = Query;
<|endoftext|>


<commit_before>import React, { Component } from 'react';

// TODO:
// - remove button
// - ticket budget
// - dispatch hours override
// - total hours for selected tickets

export default class Queue extends Component {
  constructor() {
    super()
  }

  render() {
    return (

Queue

{this.props.selectedTickets.length} tickets selected.

          {this.props.selectedTickets.map(ticket => (

{ticket.id}

          ))}

    );
  }
}

<commit_msg>Show ticket info and budget<commit_after>import React, { Component } from 'react';

// TODO:
// - remove button
// - dispatch hours override
// - total hours for selected tickets

export default class Queue extends Component {
  constructor() {
    super()
  }

  render() {
    return (

Queue

{this.props.selectedTickets.length} tickets selected.

          {this.props.selectedTickets.map(ticket => (

              {ticket.id} — {ticket.company.name} — {ticket.summary} {' '}
              ({ticket.actualHours} / {ticket.budgetHours})

          ))}

    );
  }
}

<|endoftext|>


<commit_before>var path = require('path'),
    current_directory = path.normalize(process.cwd()),
    fs = require('fs'),
    _ = require('underscore'),
    minimatch = require('minimatch'),
    output_path = require('../utils/output_path'),
    yaml_parser = require('../utils/yaml_parser'),
    watcher = require('../watcher'),
    roots = require('../index'),
    Compiler = require('../compiler'),
    server = require('../server'),
    colors = require('colors');

var compiler = new Compiler();

var _watch = function(){

  // add in the livereload function
  var socket_script = "<script>" + fs.readFileSync(path.join(__dirname, '../../templates/reload/reload.min.js'), 'utf8') + "</script>";
  var spinner_html = fs.readFileSync(path.join(__dirname, '../../templates/reload/spinner.html'));
  global.options.locals.livereload = socket_script + spinner_html;

  // compile once and run the local server when ready
  roots.compile_project(current_directory, function(){ server.start(current_directory); });

  // watch the project for changes and reload
  watcher.watch_directory(current_directory, _.debounce(watch_function, 500));

  function watch_function(file){

    server.compiling();

    // if there was an error, the whole project needs to be recompiled to
    // get rid of the error message
    if (global.options.error) {
      global.options.error = false;
      return roots.compile_project(current_directory, server.reload);
    }

    // if it's a dynamic file, the entire project needs to be recompiled
    // so that references to it show up in other files
    if (yaml_parser.detect(file.fullPath)){
      return roots.compile_project(current_directory, server.reload);
    }

    // ignored files that are modified actively are often dependencies
    // for another non-ignored file. Until we have something like assetgraph
    // in this project, the safest approach is to recompile the whole project
    // when an ignored file is modified.
    var ignored = global.options.ignore_files;

    for (var i = 0; i < ignored.length; i++){
      if (minimatch(path.basename(file.path), ignored[i])) {
        return roots.compile_project(current_directory, server.reload);
      }
    }

    // otherwise, just compile the single file that was changed
    if (fs.existsSync(file.fullPath)){
      roots.compile_project(file.fullPath, server.reload);
    } else {
      try {
        fs.unlinkSync(output_path(file.fullPath));
      } catch(e) {
        console.log("Error Unlinking File".inverse.red);
        console.log(e);
      }
      server.reload();
    }
  }

};

module.exports = { execute: _watch, needs_config: true };
<commit_msg>fixed a little bug in file ignore watch detection, closes #146<commit_after>var path = require('path'),
    current_directory = path.normalize(process.cwd()),
    fs = require('fs'),
    _ = require('underscore'),
    minimatch = require('minimatch'),
    output_path = require('../utils/output_path'),
    yaml_parser = require('../utils/yaml_parser'),
    watcher = require('../watcher'),
    roots = require('../index'),
    Compiler = require('../compiler'),
    server = require('../server'),
    colors = require('colors');

var compiler = new Compiler();

var _watch = function(){

  // add in the livereload function
  var socket_script = "<script>" + fs.readFileSync(path.join(__dirname, '../../templates/reload/reload.min.js'), 'utf8') + "</script>";
  var spinner_html = fs.readFileSync(path.join(__dirname, '../../templates/reload/spinner.html'));
  global.options.locals.livereload = socket_script + spinner_html;

  // compile once and run the local server when ready
  roots.compile_project(current_directory, function(){ server.start(current_directory); });

  // watch the project for changes and reload
  watcher.watch_directory(current_directory, _.debounce(watch_function, 500));

  function watch_function(file){

    server.compiling();

    // if there was an error, the whole project needs to be recompiled to
    // get rid of the error message
    if (global.options.error) {
      options.debug.log('error, reloading project')
      global.options.error = false;
      return roots.compile_project(current_directory, server.reload);
    }

    // if it's a dynamic file, the entire project needs to be recompiled
    // so that references to it show up in other files
    if (yaml_parser.detect(file.fullPath)){
      options.debug.log('dynamic file changed, reloading project')
      return roots.compile_project(current_directory, server.reload);
    }

    // ignored files that are modified actively are often dependencies
    // for another non-ignored file. Until we have something like assetgraph
    // in this project, the safest approach is to recompile the whole project
    // when an ignored file is modified.
    var ignored = global.options.ignore_files;

    for (var i = 0; i < ignored.length; i++){
      if (minimatch(path.basename(file.path), ignored[i].slice(1))) {
        options.debug.log('ignored file changed, reloading project')
        return roots.compile_project(current_directory, server.reload);
      }
    }

    // otherwise, just compile the single file that was changed
    if (fs.existsSync(file.fullPath)){
      options.debug.log('single file compile')
      roots.compile_project(file.fullPath, server.reload);
    } else {
      try {
        fs.unlinkSync(output_path(file.fullPath));
      } catch(e) {
        console.log("Error Unlinking File".inverse.red);
        console.log(e);
      }
      server.reload();
    }
  }

};

module.exports = { execute: _watch, needs_config: true };
<|endoftext|>