<commit_before>import childProcess from 'child_process'
import fs from 'fs'
import path from 'path'

import { sleep } from '../utils'

export function start () {
  const { app, program } = this
  this.checkProject()
  if (program.shell === 'concurrently') {
    this.concurrentlyCommands = []
  }
  this.backendStart()
  this.bundlerStart()
  if (program.shell === 'concurrently') {
    const concurrentlyCommandsString = this.concurrentlyCommands
      .map(concurrentlyCommand => `\"${concurrentlyCommand}\"`)
      .join(' ')
    const command = `${app.concurrentlyDir} --kill-others ${concurrentlyCommandsString}`
    this.consoleLog(command)
    childProcess.execSync(command, { stdio: [0, 1, 2] })
  }
}

export function backendStart () {
  this.checkProject()
  const { backend, program } = this
  if (!backend) return
  this.startProviders()
  program.type = 'localhost'
  this.startServers()
}

export function startProviders () {
  const { program } = this
  program.method = 'startProvider'
  this.mapInProviders()
}

export function startProvider () {
  this.checkProject()
  const { program, provider } = this
  if (!provider) return
  if (program.data === 'localhost' && fs.existsSync(provider.startDir)) {
    const psResult = childProcess.execSync(
      this.getPsProviderCommand()
    ).toString('utf-8')
    if (psResult.trim() === '') {
      childProcess.execSync(this.getStartProviderCommand())
      sleep(2000)
    } else {
      console.log(`${provider.name} localhost is already starting`)
    }
  }
}

export function getPsProviderCommand () {
  return ''
}

export function getStartProviderCommand () {
  const { app, program, provider } = this
  let command = `cd ${provider.dataDir} && sh start.sh`
  return command
}

export function startServers () {
  const { program } = this
  program.method = 'startServer'
  this.mapInServers()
}

export function startServer () {
  this.checkProject()
  const { program, run, server } = this
  if (!server) return
  const command = this.getStartServerCommand()
  if (program.shell !== 'concurrently') {
    this.consoleInfo(`Let\'s start the ${server.name} server`)
    this.consoleLog(command)
    childProcess.execSync(command, { stdio: [0, 1, 2] })
    console.log(`${server.name} serves at http://localhost:${run.port}`)
  } else {
    this.concurrentlyCommands.push(command)
  }
}

export function getStartServerCommand () {
  const { app, program, server, type } = this
  const commands = []
  const fileName = 'localhost_start.sh'
  commands.push(`export MODE=${type.name}`)
  commands.push(`cd ${server.dir}`)
  commands.push(`sh scripts/${fileName}`)
  let command = commands.join(' && ')
  if (app.venvDir) {
    command = `source ${app.venvDir}/bin/activate && ${command}`
  }
  return command
}

export function openServerWindow () {
  const command = this.getOpenServerWindow()
  childProcess.execSync(command)
}

export function bundlerStart () {
  const { app, program, project } = this
  if (!fs.existsSync(path.join(project.dir, 'bundler'))) return
  let command = `cd ${project.dir} && sh bin/localhost_bundle.sh`
  if (program.shell === 'concurrently') {
    this.concurrentlyCommands.push(command)
  } else {
    this.consoleInfo('Let\'s start the bundler')
    this.consoleLog(command)
    childProcess.execSync(command, { stdio: [0, 1, 2] })
  }
}
<commit_msg>added comments in start method<commit_after>// START SUB TASK
// start is the task that will run your project locally.
// - it goes to each server and execute their scripts/localhost_start.sh
// script.
// - it runs the server of assets and scripts that you may have if you have a frontend
// bundler like webpack.

import childProcess from 'child_process'
import fs from 'fs'
import path from 'path'

import { sleep } from '../utils'

export function start () {
  const { app, program } = this
  this.checkProject()
  if (program.shell === 'concurrently') {
    this.concurrentlyCommands = []
  }
  this.backendStart()
  this.bundlerStart()
  if (program.shell === 'concurrently') {
    const concurrentlyCommandsString = this.concurrentlyCommands
      .map(concurrentlyCommand => `\"${concurrentlyCommand}\"`)
      .join(' ')
    const command = `${app.concurrentlyDir} --kill-others ${concurrentlyCommandsString}`
    this.consoleLog(command)
    childProcess.execSync(command, { stdio: [0, 1, 2] })
  }
}

export function backendStart () {
  this.checkProject()
  const { backend, program } = this
  if (!backend) return
  this.startProviders()
  program.type = 'localhost'
  this.startServers()
}

export function startProviders () {
  const { program } = this
  program.method = 'startProvider'
  this.mapInProviders()
}

export function startProvider () {
  this.checkProject()
  const { program, provider } = this
  if (!provider) return
  if (program.data === 'localhost' && fs.existsSync(provider.startDir)) {
    const psResult = childProcess.execSync(
      this.getPsProviderCommand()
    ).toString('utf-8')
    if (psResult.trim() === '') {
      childProcess.execSync(this.getStartProviderCommand())
      sleep(2000)
    } else {
      console.log(`${provider.name} localhost is already starting`)
    }
  }
}

export function getPsProviderCommand () {
  return ''
}

export function getStartProviderCommand () {
  const { app, program, provider } = this
  let command = `cd ${provider.dataDir} && sh start.sh`
  return command
}

export function startServers () {
  const { program } = this
  program.method = 'startServer'
  this.mapInServers()
}

export function startServer () {
  this.checkProject()
  const { program, run, server } = this
  if (!server) return
  const command = this.getStartServerCommand()
  if (program.shell !== 'concurrently') {
    this.consoleInfo(`Let\'s start the ${server.name} server`)
    this.consoleLog(command)
    childProcess.execSync(command, { stdio: [0, 1, 2] })
    console.log(`${server.name} serves at http://localhost:${run.port}`)
  } else {
    this.concurrentlyCommands.push(command)
  }
}

export function getStartServerCommand () {
  const { app, program, server, type } = this
  const commands = []
  const fileName = 'localhost_start.sh'
  commands.push(`export MODE=${type.name}`)
  commands.push(`cd ${server.dir}`)
  commands.push(`sh scripts/${fileName}`)
  let command = commands.join(' && ')
  if (app.venvDir) {
    command = `source ${app.venvDir}/bin/activate && ${command}`
  }
  return command
}

export function openServerWindow () {
  const command = this.getOpenServerWindow()
  childProcess.execSync(command)
}

export function bundlerStart () {
  const { app, program, project } = this
  if (!fs.existsSync(path.join(project.dir, 'bundler'))) return
  let command = `cd ${project.dir} && sh bin/localhost_bundle.sh`
  if (program.shell === 'concurrently') {
    this.concurrentlyCommands.push(command)
  } else {
    this.consoleInfo('Let\'s start the bundler')
    this.consoleLog(command)
    childProcess.execSync(command, { stdio: [0, 1, 2] })
  }
}
<|endoftext|>


<commit_before>/*jshint -W030, -W020 */

DEBUG = !!process.env.VELOCITY_DEBUG;

(function () {

  'use strict';

  var path     = Npm.require('path'),
      fs       = Npm.require('fs-extra'),
      freeport = Npm.require('freeport');

  // this library extends the string prototype
  Npm.require('colors');

  var FRAMEWORK_NAME = 'cucumber';
  var WATCH_TAG = '@dev';
  var BINARY = process.env.CHIMP_PATH || Npm.require('chimp').bin;
  if (
    process.env.NODE_ENV !== 'development' || !process.env.IS_MIRROR ||
    process.env[FRAMEWORK_NAME.toUpperCase()] === '0' ||
    process.env.VELOCITY === '0' ||
    process.env.FRAMEWORK.indexOf(FRAMEWORK_NAME) !== 0
  ) {
    return;
  }

  DEBUG && console.log('[xolvio:cucumber] Mirror server is initializing');

  var _velocityConnection,
      _velocityTestFiles,
      _chimpProc,
      _chimpServerPort,
      _runningParallelTest;

  Meteor.startup(_startChimp);

  Meteor.methods({
    handshake: function () {
      this.unblock();
      DEBUG && console.log('[xolvio:cucumber] Received handshake from Chimp.');
      _init();
    },
    runAll: function () {
      this.unblock();
      DEBUG && console.log('[xolvio:cucumber] Running all specs.');
      _runSingleExecutionMode(true);
    }
  });

  function _findAndRun () {
    DEBUG && console.log('[xolvio:cucumber] Find and run triggered', arguments);

    var findAndRun = function () {
      var feature = _velocityConnection.call('velocity/returnTODOTestAndMarkItAsDOING', {framework: FRAMEWORK_NAME});
      if (feature) {
        _runningParallelTest = true;
        _run(feature, findAndRun);
      }

    };

    if (!!process.env.CUCUMBER_NODES) {
      DEBUG && console.log('[xolvio:cucumber] Running in split-features mode');
      !_runningParallelTest && findAndRun();
    } else {
      DEBUG && console.log('[xolvio:cucumber] Running in batch-features mode.');
      _run();
    }

  }

  function _init () {

    DEBUG && console.log('[xolvio:cucumber] Connecting to hub');

    _velocityConnection = DDP.connect(process.env.PARENT_URL);
    _velocityConnection.subscribe('VelocityTestFiles');

    _velocityTestFiles = new Mongo.Collection('velocityTestFiles', {
      connection: _velocityConnection
    });
    var cursor = _velocityTestFiles.find({targetFramework: FRAMEWORK_NAME});

    _velocityConnection.onReconnect = function () {
      DEBUG && console.log('[xolvio:cucumber] Connected to hub.');
      var debouncedRun = _.debounce(Meteor.bindEnvironment(_findAndRun), 600);
      cursor.observe({
        added: debouncedRun,
        removed: debouncedRun,
        changed: debouncedRun
      });

      process.on('SIGUSR2', Meteor.bindEnvironment(function () {
        DEBUG && console.log('[xolvio:cucumber] SIGUSR2 signal seen');
        debouncedRun.apply(this, arguments);
      }));
      process.on('message', Meteor.bindEnvironment(function (message) {
        DEBUG && console.log('[xolvio:cucumber] Process message seen', message);
        if (message.refresh && message.refresh === 'client') {
          debouncedRun();
        }
      }));

    };
  }

  function _run (feature, cb) {
    if (feature) {
      _runParallelExecutionMode(feature, cb);
    } else {
      _runSingleExecutionMode();
    }
  }

  function _runSingleExecutionMode (runAll) {
    console.log('[xolvio:cucumber] Cucumber is running'.yellow);
    _velocityConnection.call('velocity/reports/reset', {framework: FRAMEWORK_NAME});

    try {
      HTTP.get('http://localhost:' + _getServerPort() + '/interrupt');

      var endPoint = runAll ? '/runAll' : '/run';

      var response = HTTP.get('http://localhost:' + _getServerPort() + endPoint);

      var results = response.data;

      if (!results) {
        console.error('[xolvio:cucumber] Bad response from Chimp server.'.red);
        console.error(response);
        _finishWithError();
        return;
      }

      DEBUG && console.log('[xolvio:cucumber] Results from Chimp:');
      DEBUG && console.log(results);

      if (results.message) {

        _velocityConnection.call('velocity/reports/submit', {

          name: 'Unhandled Promise Rejection',
          framework: FRAMEWORK_NAME,
          result: 'failed',
          failureMessage: 'Did you forget to add ".catch" to a promise?',
          failureType: results.message,
          failureStackTrace: results.stack
        });

      }

      if (results.length === 0) {
        console.log('[xolvio:cucumber] No features found. Be sure to annotate scenarios'.yellow,
          'you want to run in watch mode with the'.yellow, WATCH_TAG.cyan, 'tag'.yellow);
        _velocityConnection.call('velocity/reports/submit', {
          name: WATCH_TAG + ' not detected',
          framework: FRAMEWORK_NAME,
          ancestors: ['No specs were run'],
          result: 'passed'
        });
      }
      _processFeatures(results);
    } catch (e) {
      console.error('[xolvio:cucumber] Bad response from Chimp server.'.red, e);
      _finishWithError();
      return;
    }
    _velocityConnection.call('velocity/reports/completed', {framework: FRAMEWORK_NAME});
  }

  function _runParallelExecutionMode (feature, cb) {
    var _error = false;

    console.log('[xolvio:cucumber] Mirror with pid', process.pid, 'is working on', feature.absolutePath, " port ", _getServerPort());

    try {
      var response = HTTP.get('http://localhost:' + _getServerPort() + '/run/' + feature.absolutePath);
      var results = JSON.parse(response.content);
      _processFeatures(results);
    }
    catch (e) {
      console.error('[xolvio:cucumber] Bad response from Chimp server.'.red, 'port: '.red, _getServerPort());
      _error = true;
    }

    if (_error) {
      if (feature.brokenPreviously) {
        _finishWithError();
      } else {
        _velocityConnection.call('velocity/featureTestFailed', {featureId: feature._id});
      }
    }
    else {
      _velocityConnection.call('velocity/featureTestDone', {featureId: feature._id});
    }

    _runningParallelTest = false;
    cb && cb();
  }

  function _finishWithError (report) {
    // attempt to kill any current runs and tell velocity we failed

    try {
      HTTP.get('http://localhost:' + _getServerPort() + '/interrupt');
    } catch (e) {
    }

    report = report || {
        name: 'An error occurred. Check the logs for more information.',
        framework: FRAMEWORK_NAME,
        result: 'failed'
      };
    _velocityConnection.call('velocity/reports/submit', report);
    _velocityConnection.call('velocity/reports/completed', {framework: FRAMEWORK_NAME});
  }

  function _startChimp () {

    var cwd = path.resolve(process.env.VELOCITY_MAIN_APP_PATH, 'tests', FRAMEWORK_NAME);

    if (!fs.existsSync(cwd)) {
      console.log('[xolvio:cucumber]'.yellow, cwd.yellow, 'does not exist. You need to '.yellow +
        'create this directory and add some features to run Cucumber.'.yellow);
      return;
    }

    var startChimpOnPort = function (err, port) {
      _chimpServerPort = port;

      DEBUG && console.log('[xolvio:cucumber] Starting Chimp');
      _chimpProc = new sanjo.LongRunningChildProcess('Chimp_' + _getServerPort());
      if (_chimpProc.isRunning()) {
        DEBUG && console.log('[xolvio:cucumber] Chimp is already running in server mode. Initting');
        _init();
        return;
      }

      var args = _getArgs();

      fs.chmodSync(BINARY, parseInt('555', 8));
      var nodePath = process.execPath;
      var nodeDir = path.dirname(nodePath);
      var env = _.clone(process.env);
      // Expose the Meteor node binary path for the script that is run
      env.PATH = nodeDir + ':' + env.PATH;
      var spawnOptions = {
        cwd: cwd,
        stdio: 'inherit',
        env: env
      };

      args.push('--server');

      args.push('--serverPort=' + _getServerPort());

      DEBUG && console.log('[xolvio:cucumber] Starting Chimp with', BINARY, args, spawnOptions);

      _chimpProc.spawn({
        command: nodePath,
        args: args,
        options: spawnOptions
      });

      DEBUG && console.log('[xolvio:cucumber] Chimp process forked with pid', _chimpProc.getPid());

    };

    if (!!process.env.CUCUMBER_NODES) {
      freeport(Meteor.bindEnvironment(startChimpOnPort))
    } else {
      var serverPort = process.env.CUCUMBER_SERVER_PORT ? process.env.CUCUMBER_SERVER_PORT : 8866;
      startChimpOnPort(null, serverPort);
    }

  }

  function _getServerPort () {
    return _chimpServerPort;
  }

  function _getScreenshotsDir () {
    var _screenshotsDir = process.env.CUCUMBER_SCREENSHOTS_DIR ||
      path.resolve(process.env.VELOCITY_MAIN_APP_PATH, 'tests', FRAMEWORK_NAME, '.screenshots');
    DEBUG && console.log('[xolvio:cucumber] Screenshots dir is', _screenshotsDir);
    return path.resolve(_screenshotsDir);
  }

  function _getArgs () {

    var args = [];

    if (process.env.CHIMP_NODE_OPTIONS) {
      args.push(process.env.CHIMP_NODE_OPTIONS);
    } else if (process.env.CHIMP_DEBUG) {
      args.push('--debug');
      args.push('--debug-brk');
    }

    args.push(BINARY);

    args.push('-r');
    args.push(path.join(process.env.VELOCITY_MAIN_APP_PATH, 'tests', 'cucumber', 'features'));
    args.push('--snippets');
    args.push('--ddp=' + process.env.ROOT_URL);
    args.push('--log=error');

    // TODO only if local / xolvio:reporter is detected
    //args.push('--simianResultEndPoint=' + process.env.PARENT_URL.substring('http://'.length) + 'xolvio/reporter/results');
    //args.push('--simianAccessToken=' + 'local');

    if (DEBUG || process.env.DEBUG) {
      args.push('--debug');
    }

    if (process.env.CHIMP_OPTIONS) {
      var chimpOptions = process.env.CHIMP_OPTIONS.split(' ');
      while (chimpOptions.length != 0) {
        args.push(chimpOptions.pop());
      }
      return args;
    }

    if (process.env.VELOCITY_CI) {
      args.push('--screenshotsOnError=true');
    }

    args.push('--screenshotsPath=' + _getScreenshotsDir());

    if (process.env.CUCUMBER_COFFEE_SNIPPETS) {
      args.push('--coffee');
    }

    if (process.env.CUCUMBER_TAGS) {
      args.push('--tags=' + process.env.CUCUMBER_TAGS);
    } else if (!process.env.VELOCITY_CI) {
      args.push('--tags=' + WATCH_TAG);
    } else {
      args.push('--tags=~@ignore');
    }

    if (process.env.CUCUMBER_FORMAT) {
      args.push('--format=' + process.env.CUCUMBER_FORMAT);
    }

    if (process.env.SIMIAN_ACCESS_TOKEN) {
      args.push('--simianAccessToken=' + process.env.SIMIAN_ACCESS_TOKEN);
    }

    if (process.env.CUCUMBER_JSON_OUTPUT) {
      args.push('--jsonOutput=' + process.env.CUCUMBER_JSON_OUTPUT);
    }

    if (process.env.WD_TIMEOUT_ASYNC_SCRIPT) {
      args.push('--timeoutsAsyncScript=' + process.env.WD_TIMEOUT_ASYNC_SCRIPT);
    }

    if (process.env.SELENIUM_BROWSER) {
      args.push('--browser=' + process.env.SELENIUM_BROWSER);
    }

    if (process.env.HUB_HOST) {
      args.push('--host=' + process.env.HUB_HOST);
    }

    if (process.env.HUB_PORT) {
      args.push('--port=' + process.env.HUB_PORT);
    }

    if (process.env.HUB_USER) {
      args.push('--user=' + process.env.HUB_USER);
    }

    if (process.env.HUB_KEY) {
      args.push('--key=' + process.env.HUB_KEY);
    }

    if (process.env.HUB_PLATFORM) {
      args.push('--platform=' + process.env.HUB_PLATFORM);
    }

    if (process.env.HUB_VERSION) {
      args.push('--version=' + process.env.HUB_VERSION);
    }

    if (process.env.CHIMP_OFFLINE) {
      args.push('--offline');
    }

    return args;

  }

  function _processFeatures (features) {
    _.each(features, function (feature) {
      _processFeature(feature);
    });
  }

  function _processFeature (feature) {
    _.each(feature.elements, function (element) {
      _processFeatureElements(element, feature);
    });
  }

  function _processFeatureElements (element, feature) {
    _.each(element.steps, function (step) {
      _processStep(element, step, feature);
    });
  }

  function _processStep (element, step, feature) {

    if (element.type === 'background') {
      return;
    }

    var report = {
      id: element.id + step.keyword + step.name,
      framework: FRAMEWORK_NAME,
      name: step.keyword + step.name,
      result: step.result.status,
      ancestors: [element.name, feature.name]
    };
    if (step.result.duration) {
      report.duration = Math.round(step.result.duration / 1000000);
    }
    if (step.result.error_message) {

      if (step.result.error_message.name) {
        report.failureType = step.result.error_message.name;
        report.failureStackTrace = _conditionError(step.result.error_message.message);
      } else {
        report.failureStackTrace = _conditionError(step.result.error_message);
      }
    }

    if (step.result.status === 'undefined') {
      report.result = 'failed';
      report.failureStackTrace = 'This step has not been defined';
    }

    if (step.result.status === 'skipped') {
      report.result = 'failed';
      report.failureStackTrace = 'This step was skipped';
    }

    if (step.result.status === 'pending') {
      report.result = 'failed';
      report.failureStackTrace = 'This step is pending';
    }

    // skip before/after if they have no errors
    if (!report.failureStackTrace && (step.keyword.trim() === 'Before' || step.keyword.trim() === 'After')) {
      return;
    }

    _velocityConnection.call('velocity/reports/submit', report);

  }

  function _conditionError (errorMessage) {

    if (DEBUG) {
      console.error(errorMessage.red);
      return errorMessage;
    }

    var msg        = '',
        insertDots = false,
        DOTS       = '  ...\n';

    try {

      if (errorMessage.indexOf('Timed out waiting for asyncrhonous') !== -1) {
        return errorMessage.substring(errorMessage.lastIndexOf('->') + 3, errorMessage.length).trim()
          + ' timed out';
      }

      _.each(errorMessage.split('\n'), function (line, index) {
        line = line.trim();
        if (index === 0) {
          msg += line;
          return;
        }
        if (line.indexOf('/tests/cucumber/') !== -1) {
          if (insertDots) {
            msg += DOTS;
            insertDots = false;
          }
          msg += ((index !== 0 ? '  ' : '') +
          line.replace(process.env.VELOCITY_MAIN_APP_PATH, '') + '\n');
        } else {
          insertDots = true;
        }
      });
      if (insertDots) {
        msg += DOTS;
      }

      // TODO deal with this error for users
      // Cannot call method 'convertScenarioOutlinesToScenarios' of undefined

      msg = msg.substring(0, msg.length);
      //console.log(msg.magenta);
    } catch (e) {
      msg = errorMessage;
      console.error(errorMessage);
    }

    return msg;
  }

})();
<commit_msg>Enabled debugging of cuke steps<commit_after>/*jshint -W030, -W020 */

DEBUG = !!process.env.VELOCITY_DEBUG;

(function () {

  'use strict';

  var path     = Npm.require('path'),
      fs       = Npm.require('fs-extra'),
      freeport = Npm.require('freeport');

  // this library extends the string prototype
  Npm.require('colors');

  var FRAMEWORK_NAME = 'cucumber';
  var WATCH_TAG = '@dev';
  var BINARY = process.env.CHIMP_PATH || Npm.require('chimp').bin;
  if (
    process.env.NODE_ENV !== 'development' || !process.env.IS_MIRROR ||
    process.env[FRAMEWORK_NAME.toUpperCase()] === '0' ||
    process.env.VELOCITY === '0' ||
    process.env.FRAMEWORK.indexOf(FRAMEWORK_NAME) !== 0
  ) {
    return;
  }

  DEBUG && console.log('[xolvio:cucumber] Mirror server is initializing');

  var _velocityConnection,
      _velocityTestFiles,
      _chimpProc,
      _chimpServerPort,
      _runningParallelTest;

  Meteor.startup(_startChimp);

  Meteor.methods({
    handshake: function () {
      this.unblock();
      DEBUG && console.log('[xolvio:cucumber] Received handshake from Chimp.');
      _init();
    },
    runAll: function () {
      this.unblock();
      DEBUG && console.log('[xolvio:cucumber] Running all specs.');
      _runSingleExecutionMode(true);
    }
  });

  function _findAndRun () {
    DEBUG && console.log('[xolvio:cucumber] Find and run triggered', arguments);

    var findAndRun = function () {
      var feature = _velocityConnection.call('velocity/returnTODOTestAndMarkItAsDOING', {framework: FRAMEWORK_NAME});
      if (feature) {
        _runningParallelTest = true;
        _run(feature, findAndRun);
      }

    };

    if (!!process.env.CUCUMBER_NODES) {
      DEBUG && console.log('[xolvio:cucumber] Running in split-features mode');
      !_runningParallelTest && findAndRun();
    } else {
      DEBUG && console.log('[xolvio:cucumber] Running in batch-features mode.');
      _run();
    }

  }

  function _init () {

    DEBUG && console.log('[xolvio:cucumber] Connecting to hub');

    _velocityConnection = DDP.connect(process.env.PARENT_URL);
    _velocityConnection.subscribe('VelocityTestFiles');

    _velocityTestFiles = new Mongo.Collection('velocityTestFiles', {
      connection: _velocityConnection
    });
    var cursor = _velocityTestFiles.find({targetFramework: FRAMEWORK_NAME});

    _velocityConnection.onReconnect = function () {
      DEBUG && console.log('[xolvio:cucumber] Connected to hub.');
      var debouncedRun = _.debounce(Meteor.bindEnvironment(_findAndRun), 600);
      cursor.observe({
        added: debouncedRun,
        removed: debouncedRun,
        changed: debouncedRun
      });

      process.on('SIGUSR2', Meteor.bindEnvironment(function () {
        DEBUG && console.log('[xolvio:cucumber] SIGUSR2 signal seen');
        debouncedRun.apply(this, arguments);
      }));
      process.on('message', Meteor.bindEnvironment(function (message) {
        DEBUG && console.log('[xolvio:cucumber] Process message seen', message);
        if (message.refresh && message.refresh === 'client') {
          debouncedRun();
        }
      }));

    };
  }

  function _run (feature, cb) {
    if (feature) {
      _runParallelExecutionMode(feature, cb);
    } else {
      _runSingleExecutionMode();
    }
  }

  function _runSingleExecutionMode (runAll) {
    console.log('[xolvio:cucumber] Cucumber is running'.yellow);
    _velocityConnection.call('velocity/reports/reset', {framework: FRAMEWORK_NAME});

    try {
      HTTP.get('http://localhost:' + _getServerPort() + '/interrupt');

      var endPoint = runAll ? '/runAll' : '/run';

      var response = HTTP.get('http://localhost:' + _getServerPort() + endPoint);

      var results = response.data;

      if (!results) {
        console.error('[xolvio:cucumber] Bad response from Chimp server.'.red);
        console.error(response);
        _finishWithError();
        return;
      }

      DEBUG && console.log('[xolvio:cucumber] Results from Chimp:');
      DEBUG && console.log(results);

      if (results.message) {

        _velocityConnection.call('velocity/reports/submit', {

          name: 'Unhandled Promise Rejection',
          framework: FRAMEWORK_NAME,
          result: 'failed',
          failureMessage: 'Did you forget to add ".catch" to a promise?',
          failureType: results.message,
          failureStackTrace: results.stack
        });

      }

      if (results.length === 0) {
        console.log('[xolvio:cucumber] No features found. Be sure to annotate scenarios'.yellow,
          'you want to run in watch mode with the'.yellow, WATCH_TAG.cyan, 'tag'.yellow);
        _velocityConnection.call('velocity/reports/submit', {
          name: WATCH_TAG + ' not detected',
          framework: FRAMEWORK_NAME,
          ancestors: ['No specs were run'],
          result: 'passed'
        });
      }
      _processFeatures(results);
    } catch (e) {
      console.error('[xolvio:cucumber] Bad response from Chimp server.'.red, e);
      _finishWithError();
      return;
    }
    _velocityConnection.call('velocity/reports/completed', {framework: FRAMEWORK_NAME});
  }

  function _runParallelExecutionMode (feature, cb) {
    var _error = false;

    console.log('[xolvio:cucumber] Mirror with pid', process.pid, 'is working on', feature.absolutePath, " port ", _getServerPort());

    try {
      var response = HTTP.get('http://localhost:' + _getServerPort() + '/run/' + feature.absolutePath);
      var results = JSON.parse(response.content);
      _processFeatures(results);
    }
    catch (e) {
      console.error('[xolvio:cucumber] Bad response from Chimp server.'.red, 'port: '.red, _getServerPort());
      _error = true;
    }

    if (_error) {
      if (feature.brokenPreviously) {
        _finishWithError();
      } else {
        _velocityConnection.call('velocity/featureTestFailed', {featureId: feature._id});
      }
    }
    else {
      _velocityConnection.call('velocity/featureTestDone', {featureId: feature._id});
    }

    _runningParallelTest = false;
    cb && cb();
  }

  function _finishWithError (report) {
    // attempt to kill any current runs and tell velocity we failed

    try {
      HTTP.get('http://localhost:' + _getServerPort() + '/interrupt');
    } catch (e) {
    }

    report = report || {
        name: 'An error occurred. Check the logs for more information.',
        framework: FRAMEWORK_NAME,
        result: 'failed'
      };
    _velocityConnection.call('velocity/reports/submit', report);
    _velocityConnection.call('velocity/reports/completed', {framework: FRAMEWORK_NAME});
  }

  function _startChimp () {

    var cwd = path.resolve(process.env.VELOCITY_MAIN_APP_PATH, 'tests', FRAMEWORK_NAME);

    if (!fs.existsSync(cwd)) {
      console.log('[xolvio:cucumber]'.yellow, cwd.yellow, 'does not exist. You need to '.yellow +
        'create this directory and add some features to run Cucumber.'.yellow);
      return;
    }

    var startChimpOnPort = function (err, port) {
      _chimpServerPort = port;

      DEBUG && console.log('[xolvio:cucumber] Starting Chimp');
      _chimpProc = new sanjo.LongRunningChildProcess('Chimp_' + _getServerPort());
      if (_chimpProc.isRunning()) {
        DEBUG && console.log('[xolvio:cucumber] Chimp is already running in server mode. Initting');
        _init();
        return;
      }

      var args = _getArgs();

      fs.chmodSync(BINARY, parseInt('555', 8));
      var nodePath = process.execPath;
      var nodeDir = path.dirname(nodePath);
      var env = _.clone(process.env);
      // Expose the Meteor node binary path for the script that is run
      env.PATH = nodeDir + ':' + env.PATH;
      var spawnOptions = {
        cwd: cwd,
        stdio: 'inherit',
        env: env
      };

      args.push('--server');

      args.push('--serverPort=' + _getServerPort());

      DEBUG && console.log('[xolvio:cucumber] Starting Chimp with', BINARY, args, spawnOptions);

      _chimpProc.spawn({
        command: nodePath,
        args: args,
        options: spawnOptions
      });

      DEBUG && console.log('[xolvio:cucumber] Chimp process forked with pid', _chimpProc.getPid());

    };

    if (!!process.env.CUCUMBER_NODES) {
      freeport(Meteor.bindEnvironment(startChimpOnPort))
    } else {
      var serverPort = process.env.CUCUMBER_SERVER_PORT ? process.env.CUCUMBER_SERVER_PORT : 8866;
      startChimpOnPort(null, serverPort);
    }

  }

  function _getServerPort () {
    return _chimpServerPort;
  }

  function _getScreenshotsDir () {
    var _screenshotsDir = process.env.CUCUMBER_SCREENSHOTS_DIR ||
      path.resolve(process.env.VELOCITY_MAIN_APP_PATH, 'tests', FRAMEWORK_NAME, '.screenshots');
    DEBUG && console.log('[xolvio:cucumber] Screenshots dir is', _screenshotsDir);
    return path.resolve(_screenshotsDir);
  }

  function _getArgs () {

    var args = [];

    if (process.env.CHIMP_NODE_OPTIONS) {
      args.push(process.env.CHIMP_NODE_OPTIONS);
    } else if (process.env.CHIMP_DEBUG) {
      args.push('--debug-brk');
    }

    args.push(BINARY);

    args.push('-r');
    args.push(path.join(process.env.VELOCITY_MAIN_APP_PATH, 'tests', 'cucumber', 'features'));
    args.push('--snippets');
    args.push('--ddp=' + process.env.ROOT_URL);
    args.push('--log=error');

    // TODO only if local / xolvio:reporter is detected
    //args.push('--simianResultEndPoint=' + process.env.PARENT_URL.substring('http://'.length) + 'xolvio/reporter/results');
    //args.push('--simianAccessToken=' + 'local');

    if (DEBUG || process.env.DEBUG) {
      args.push('--debug');
    }

    if (process.env.CHIMP_OPTIONS) {
      var chimpOptions = process.env.CHIMP_OPTIONS.split(' ');
      while (chimpOptions.length != 0) {
        args.push(chimpOptions.pop());
      }
      return args;
    }

    if (process.env.VELOCITY_CI) {
      args.push('--screenshotsOnError=true');
    }

    args.push('--screenshotsPath=' + _getScreenshotsDir());

    if (process.env.CUCUMBER_COFFEE_SNIPPETS) {
      args.push('--coffee');
    }

    if (process.env.CUCUMBER_TAGS) {
      args.push('--tags=' + process.env.CUCUMBER_TAGS);
    } else if (!process.env.VELOCITY_CI) {
      args.push('--tags=' + WATCH_TAG);
    } else {
      args.push('--tags=~@ignore');
    }

    if (process.env.CUCUMBER_FORMAT) {
      args.push('--format=' + process.env.CUCUMBER_FORMAT);
    }

    if (process.env.SIMIAN_ACCESS_TOKEN) {
      args.push('--simianAccessToken=' + process.env.SIMIAN_ACCESS_TOKEN);
    }

    if (process.env.CUCUMBER_JSON_OUTPUT) {
      args.push('--jsonOutput=' + process.env.CUCUMBER_JSON_OUTPUT);
    }

    if (process.env.WD_TIMEOUT_ASYNC_SCRIPT) {
      args.push('--timeoutsAsyncScript=' + process.env.WD_TIMEOUT_ASYNC_SCRIPT);
    }

    if (process.env.SELENIUM_BROWSER) {
      args.push('--browser=' + process.env.SELENIUM_BROWSER);
    }

    if (process.env.HUB_HOST) {
      args.push('--host=' + process.env.HUB_HOST);
    }

    if (process.env.HUB_PORT) {
      args.push('--port=' + process.env.HUB_PORT);
    }

    if (process.env.HUB_USER) {
      args.push('--user=' + process.env.HUB_USER);
    }

    if (process.env.HUB_KEY) {
      args.push('--key=' + process.env.HUB_KEY);
    }

    if (process.env.HUB_PLATFORM) {
      args.push('--platform=' + process.env.HUB_PLATFORM);
    }

    if (process.env.HUB_VERSION) {
      args.push('--version=' + process.env.HUB_VERSION);
    }

    if (process.env.CHIMP_OFFLINE) {
      args.push('--offline');
    }

    if (process.env.DEBUG_CUCUMBER) {
      args.push('--debugCucumber=' + process.env.DEBUG_CUCUMBER);
    }

    if (process.env.DEBUG_BRK_CUCUMBER) {
      args.push('--debugBrkCucumber=' + process.env.DEBUG_BRK_CUCUMBER);
    }

    return args;

  }

  function _processFeatures (features) {
    _.each(features, function (feature) {
      _processFeature(feature);
    });
  }

  function _processFeature (feature) {
    _.each(feature.elements, function (element) {
      _processFeatureElements(element, feature);
    });
  }

  function _processFeatureElements (element, feature) {
    _.each(element.steps, function (step) {
      _processStep(element, step, feature);
    });
  }

  function _processStep (element, step, feature) {

    if (element.type === 'background') {
      return;
    }

    var report = {
      id: element.id + step.keyword + step.name,
      framework: FRAMEWORK_NAME,
      name: step.keyword + step.name,
      result: step.result.status,
      ancestors: [element.name, feature.name]
    };
    if (step.result.duration) {
      report.duration = Math.round(step.result.duration / 1000000);
    }
    if (step.result.error_message) {

      if (step.result.error_message.name) {
        report.failureType = step.result.error_message.name;
        report.failureStackTrace = _conditionError(step.result.error_message.message);
      } else {
        report.failureStackTrace = _conditionError(step.result.error_message);
      }
    }

    if (step.result.status === 'undefined') {
      report.result = 'failed';
      report.failureStackTrace = 'This step has not been defined';
    }

    if (step.result.status === 'skipped') {
      report.result = 'failed';
      report.failureStackTrace = 'This step was skipped';
    }

    if (step.result.status === 'pending') {
      report.result = 'failed';
      report.failureStackTrace = 'This step is pending';
    }

    // skip before/after if they have no errors
    if (!report.failureStackTrace && (step.keyword.trim() === 'Before' || step.keyword.trim() === 'After')) {
      return;
    }

    _velocityConnection.call('velocity/reports/submit', report);

  }

  function _conditionError (errorMessage) {

    if (DEBUG) {
      console.error(errorMessage.red);
      return errorMessage;
    }

    var msg        = '',
        insertDots = false,
        DOTS       = '  ...\n';

    try {

      if (errorMessage.indexOf('Timed out waiting for asyncrhonous') !== -1) {
        return errorMessage.substring(errorMessage.lastIndexOf('->') + 3, errorMessage.length).trim()
          + ' timed out';
      }

      _.each(errorMessage.split('\n'), function (line, index) {
        line = line.trim();
        if (index === 0) {
          msg += line;
          return;
        }
        if (line.indexOf('/tests/cucumber/') !== -1) {
          if (insertDots) {
            msg += DOTS;
            insertDots = false;
          }
          msg += ((index !== 0 ? '  ' : '') +
          line.replace(process.env.VELOCITY_MAIN_APP_PATH, '') + '\n');
        } else {
          insertDots = true;
        }
      });
      if (insertDots) {
        msg += DOTS;
      }

      // TODO deal with this error for users
      // Cannot call method 'convertScenarioOutlinesToScenarios' of undefined

      msg = msg.substring(0, msg.length);
      //console.log(msg.magenta);
    } catch (e) {
      msg = errorMessage;
      console.error(errorMessage);
    }

    return msg;
  }

})();
<|endoftext|>


<commit_before>MODEL({
  name: 'TodoDAO', extendsModel: 'ProxyDAO',
  methods: { put: function(issue, s) {
    if (!issue.text) this.remove(issue.id, { remove: s && s.put }); else this.SUPER(issue, s);
  } }
});

MODEL({
  name: 'Todo',
  properties: [
    'id',
    { name: 'completed', model_: 'BooleanProperty' },
    { name: 'text', preSet: function (_, text) { return text.trim(); } }
  ],
  templates: [ function toDetailHTML() {/*

        $$completed{className: 'toggle'} $$text{mode: 'read-only', tagName: 'label'}
        <button class="destroy" id="<%= this.on('click', function() { this.parent.dao.remove(this.data); }) %>"></button>

      $$text{className: 'edit'}

    <%
      var toEdit    = function() { DOM.setClass(this.$, 'editing'); this.textView.focus(); }.bind(this);
      var toDisplay = function() { DOM.setClass(this.$, 'editing', false); }.bind(this);
      this.on('dblclick', toEdit, this.id);
      this.on('blur', toDisplay, this.textView.id);
      this.textView.subscribe(this.textView.ESCAPE, toDisplay);
      this.setClass('completed', function() { return this.data.completed; }.bind(this), this.id);
    %> */} ]
});

MODEL({
  name: 'Controller',
  properties: [
    {
      name: 'input',
      setter: function(text) {
        if (!text) return;
        this.dao.put(Todo.create({text: text}));
        this.propertyChange('input', text, '');
      },
      view: { model_: 'TextFieldView', placeholder: 'What needs to be done?' }
    },
    { name: 'dao' },
    { name: 'filteredDAO',    model_: 'DAOProperty', view: { model_: 'DAOListView' } },
    { name: 'completedCount', model_: 'IntProperty' },
    { name: 'activeCount',    model_: 'IntProperty', postSet: function(_, c) { this.toggle = !c; }},
    { name: 'toggle',         model_: 'BooleanProperty', postSet: function(_, n) {
      if ( n == this.activeCount > 0 ) this.dao.update(SET(Todo.COMPLETED, n));
    }},
    {
      name: 'query',
      postSet: function(_, q) { this.filteredDAO = this.dao.where(q); },
      defaultValue: TRUE,
      view: { model_: 'ChoiceListView', choices: [ [ TRUE, 'All' ], [ NOT(Todo.COMPLETED), 'Active' ], [ Todo.COMPLETED, 'Completed' ] ] }
    } ],
  actions: [{
    name: 'clear',
    labelFn:   function() { return 'Clear completed (' + this.completedCount + ')'; },
    isEnabled: function() { return this.completedCount; },
    action:    function() { this.dao.where(Todo.COMPLETED).removeAll(); }
  }],
  listeners: [ {
    name: 'onDAOUpdate',
    isFramed: true,
    code: function() {
      this.dao.select(GROUP_BY(Todo.COMPLETED, COUNT()))(function (q) {
        this.completedCount = q.groups[true];
        this.activeCount = q.groups[false];
      }.bind(this));
    }}],
  methods: {
    init: function() {
      this.SUPER();
      this.filteredDAO = this.dao = TodoDAO.create({
        delegate: EasyDAO.create({model: Todo, seqNo: true, daoType: 'StorageDAO', name: 'todos-foam'}) });
      this.dao.listen(this.onDAOUpdate);
      this.onDAOUpdate();
    }},
  templates: [
    function CSS() {/* #filters .selected { font-weight: bold; } #filters li { margin: 4px; } .actionButton-clear:disabled { display: none; } */},
    function toDetailHTML() {/*

todos
$$input{id: 'new-todo'}

        $$toggle{id: 'toggle-all', showLabel: false} $$filteredDAO{tagName: 'ul', id: 'todo-list'}

          $$activeCount{mode: 'read-only'} item<%# this.data.activeCount == 1 ? '' : 's' %> left
         $$query{id: 'filters'} $$clear{id: 'clear-completed'}

Double-click to edit a todo

Created by Kevin Greer

      {{{FOAM_POWERED}}}
Part of TodoMVC

    <%
      var f = function() { return this.completedCount + this.activeCount == 0; }.bind(this.data);
      this.setClass('hidden', f, 'main');
      this.setClass('hidden', f, 'footer');
      Events.link(this.X.memento, this.queryView.label$);
    %>
    */}]});
<commit_msg>Shortened Todo_short.js.<commit_after>MODEL({
  name: 'TodoDAO', extendsModel: 'ProxyDAO',
  methods: { put: function(issue, s) {
    if (!issue.text) this.remove(issue.id, { remove: s && s.put }); else this.SUPER(issue, s);
  }}});

MODEL({
  name: 'Todo',
  properties: [
    'id', { name: 'completed', model_: 'BooleanProperty' },
    { name: 'text', preSet: function (_, text) { return text.trim(); } }
  ],
  templates: [ function toDetailHTML() {/*

        $$completed{className: 'toggle'} $$text{mode: 'read-only', tagName: 'label'}
        <button class="destroy" id="<%= this.on('click', function() { this.parent.dao.remove(this.data); }) %>"></button>

      $$text{className: 'edit'}

 <%
      var toDisplay = function() { DOM.setClass(this.$, 'editing', false); }.bind(this);
      this.on('dblclick', function() { DOM.setClass(this.$, 'editing'); this.textView.focus(); }.bind(this), this.id);
      this.on('blur', toDisplay, this.textView.id);
      this.textView.subscribe(this.textView.ESCAPE, toDisplay);
      this.setClass('completed', function() { return this.data.completed; }.bind(this), this.id);
    %> */}]});

MODEL({
  name: 'Controller',
  properties: [
    {
      name: 'input',
      setter: function(text) {
        if (!text) return;
        this.dao.put(Todo.create({text: text}));
        this.propertyChange('input', text, '');
      },
      view: { model_: 'TextFieldView', placeholder: 'What needs to be done?' }
    },
    { name: 'dao' },
    { name: 'filteredDAO',    model_: 'DAOProperty', view: { model_: 'DAOListView' } },
    { name: 'completedCount', model_: 'IntProperty' },
    { name: 'activeCount',    model_: 'IntProperty', postSet: function(_, c) { this.toggle = !c; }},
    { name: 'toggle',         model_: 'BooleanProperty', postSet: function(_, n) {
      if ( n == this.activeCount > 0 ) this.dao.update(SET(Todo.COMPLETED, n));
    }},
    {
      name: 'query',
      postSet: function(_, q) { this.filteredDAO = this.dao.where(q); },
      defaultValue: TRUE,
      view: { model_: 'ChoiceListView', choices: [ [ TRUE, 'All' ], [ NOT(Todo.COMPLETED), 'Active' ], [ Todo.COMPLETED, 'Completed' ] ] }
    } ],
  actions: [{
    name: 'clear',
    labelFn:   function() { return 'Clear completed (' + this.completedCount + ')'; },
    isEnabled: function() { return this.completedCount; },
    action:    function() { this.dao.where(Todo.COMPLETED).removeAll(); }
  }],
  listeners: [ {
    name: 'onDAOUpdate',
    isFramed: true,
    code: function() {
      this.dao.select(GROUP_BY(Todo.COMPLETED, COUNT()))(function (q) {
        this.completedCount = q.groups[true];
        this.activeCount = q.groups[false];
      }.bind(this));
    }}],
  methods: {
    init: function() {
      this.SUPER();
      this.filteredDAO = this.dao = TodoDAO.create({
        delegate: EasyDAO.create({model: Todo, seqNo: true, daoType: 'StorageDAO', name: 'todos-foam'}) });
      this.dao.listen(this.onDAOUpdate);
      this.onDAOUpdate();
    }},
  templates: [
    function CSS() {/* #filters .selected { font-weight: bold; } #filters li { margin: 4px; } .actionButton-clear:disabled { display: none; } */},
    function toDetailHTML() {/*

todos
$$input{id: 'new-todo'}

        $$toggle{id: 'toggle-all', showLabel: false} $$filteredDAO{tagName: 'ul', id: 'todo-list'}

          $$activeCount{mode: 'read-only'} item<%# this.data.activeCount == 1 ? '' : 's' %> left
         $$query{id: 'filters'} $$clear{id: 'clear-completed'}

Double-click to edit a todo

Created by Kevin Greer

      {{{FOAM_POWERED}}}
Part of TodoMVC

    <%
      var f = function() { return this.completedCount + this.activeCount == 0; }.bind(this.data);
      this.setClass('hidden', f, 'main');
      this.setClass('hidden', f, 'footer');
      Events.link(this.X.memento, this.queryView.label$);
    %>
    */}]});
<|endoftext|>


<commit_before>const setLocal = (k,v) =>
  localStorage.setItem(`__flint.state.${k}`, JSON.stringify(v))
const getLocal = (k,d) =>
  JSON.parse(localStorage.getItem(`__flint.state.${k}`)) || d

function findPath(node) {
  if (!node || !node.getAttribute) return null
  const flintid = node.__flintID
  if (flintid) return flintid
  else return findPath(node.parentNode)
}

view Inspector {
  view.pause()

  let hudActive = false
  let showTemp = false
  let temp = null
  let views = []
  let clickOff
  let keys = {}
  let lastTarget = null

  function inspect(path) {
    if (!path || path === temp) return
    temp = path
    view.update()
  }

  function mouseMove({ target }) {
    lastTarget = target
    if (hudActive) inspect(findPath(lastTarget))
  }

  function removeTemp() {
    temp = null
    view.update()
  }

  function close(path, e) {
    if (e) { e.stopPropagation() }

    views = views.filter(_id => _id != path)
    setTimeout(view.update, 100)
  }

  function glue(e) {
    const path = findPath(e.target)

    /* toggle whether views has path */
    if (views.indexOf(path) > -1) {
      close(path)
    } else {
      views.push(path)
      view.update()
    }
    return false
  }

  function showInspect() {
    inspect(findPath(lastTarget))
    hudActive = true
    clickOff = on(window, 'click', glue)
  }

  function hideInspect() {
    hudActive = false
    clickOff()
    removeTemp()
  }

  function write(path, data) {
    console.log('writing', path, data)
    const name  = data[1][0]
    const current = _Flint.getCache[path][name]
    let value = data[1][1]
    console.log('current is', current)

    if (typeof current == 'number') {
      value = +value
    }
    _Flint.setCache(path, name, value)
    _Flint.inspectorRefreshing = path
    _Flint.getInitialStates[path]()
    _Flint.viewsAtPath[path].forceUpdate()
    _Flint.inspectorRefreshing = null
    view.update()
  }

  const isAlt = cb => e => e.keyIdentifier === 'Alt' && cb()
  let hoverOff = on(window, 'mousemove', mouseMove)

  on(window, 'keydown', isAlt(showInspect))
  on(window, 'keyup', isAlt(hideInspect))

  <views>
    <Inspector.View
      repeat={views}
      path={_}
      writeBack={write}
      onClose={e => close(_, e)}
    />

    <Inspector.View
      if={temp}
      path={temp}
      writeBack={write}
      onClose={removeTemp}
    />
  </views>

  $ = {
    position: 'fixed',
    top: 0, right: 0,
    padding: 2
  }
}

<commit_msg>fix things with inspector<commit_after>const setLocal = (k,v) =>
  localStorage.setItem(`__flint.state.${k}`, JSON.stringify(v))
const getLocal = (k,d) =>
  JSON.parse(localStorage.getItem(`__flint.state.${k}`)) || d

function findPath(node) {
  if (!node || !node.getAttribute) return null
  const flintid = node.__flintID
  if (flintid) return flintid
  else return findPath(node.parentNode)
}

view Inspector {
  view.pause()

  let hudActive = false
  let showTemp = false
  let temp = null
  let views = []
  let clickOff
  let keys = {}
  let lastTarget = null

  function inspect(path) {
    if (!path || path === temp) return
    temp = path
    view.update()
  }

  function mouseMove({ target }) {
    lastTarget = target
    if (hudActive) inspect(findPath(lastTarget))
  }

  function removeTemp() {
    temp = null
    view.update()
  }

  function close(path, e) {
    if (e) { e.stopPropagation() }

    views = views.filter(_id => _id != path)
    setTimeout(view.update, 100)
  }

  function glue(e) {
    const path = findPath(e.target)

    /* toggle whether views has path */
    if (views.indexOf(path) > -1) {
      close(path)
    } else {
      views.push(path)
      view.update()
    }
    return false
  }

  function showInspect() {
    inspect(findPath(lastTarget))
    hudActive = true
    clickOff = on.click(window, glue)
  }

  function hideInspect() {
    hudActive = false
    clickOff()
    removeTemp()
  }

  function write(path, data) {
    console.log('writing', path, data)
    const name  = data[1][0]
    const current = _Flint.getCache[path][name]
    let value = data[1][1]
    console.log('current is', current)

    if (typeof current == 'number') {
      value = +value
    }
    _Flint.setCache(path, name, value)
    _Flint.inspectorRefreshing = path
    _Flint.getInitialStates[path]()
    _Flint.viewsAtPath[path].forceUpdate()
    _Flint.inspectorRefreshing = null
    view.update()
  }

  const isAlt = cb => e => e.keyIdentifier === 'Alt' && cb()
  let hoverOff = on.mousemove(window, mouseMove)

  on.keydown(window, isAlt(showInspect))
  on.keyup(window, isAlt(hideInspect))

  <views>
    <Inspector.View
      repeat={views}
      path={_}
      writeBack={write}
      onClose={e => close(_, e)}
    />

    <Inspector.View
      if={temp}
      path={temp}
      writeBack={write}
      onClose={removeTemp}
    />
  </views>

  $ = {
    position: 'fixed',
    top: 0, right: 0,
    padding: 2
  }
}

<|endoftext|>


<commit_before>const t = require('tcomb')

const location = t.struct({
    lat: t.Num,
    long: t.Num
})

const step = t.struct({
    location: location,
    supplier: t.Str,
    physicalQuality:t.maybe(Rating),
    chemicalContaminents:t.maybe(Rating),
    microbialSafety:t.maybe(Rating),
    temperatureControl:t.maybe(Rating)
})

// a predicate is a function with signature: (x) -> boolean
const predicate = function (x) { return x>-1 || x<=5 };

// a positive number
const Rating = t.subtype(t.Num, predicate, 'Positive');

const stamp = t.struct({
    locationName: t.Str,
    geoloc:location,
    facilityName: t.Str,
    postCode:t.Str,
    FSA: t.Str,
    physicalQuality:t.maybe(Rating),
    chemicalContaminents:t.maybe(Rating),
    microbialSafety:t.maybe(Rating),
    temperatureControl:t.maybe(Rating)
});

const Passport = t.struct({
    itemId: t.Num,
    name:t.Str,
    stamps: t.list(stamp),
    links: t.list(t.Number)
});

module.exports = {
    step: step,
    Passport: Passport,
    stamp:stamp,
}<commit_msg>query not params<commit_after>const t = require('tcomb')

const location = t.struct({
    lat: t.Num,
    long: t.Num
})
// a predicate is a function with signature: (x) -> boolean
const predicate = function (x) { return x>-1 || x<=5 };

// a positive number
const Rating = t.subtype(t.Num, predicate, 'Positive');

const step = t.struct({
    location: location,
    supplier: t.Str,
    physicalQuality:t.maybe(Rating),
    chemicalContaminents:t.maybe(Rating),
    microbialSafety:t.maybe(Rating),
    temperatureControl:t.maybe(Rating)
})

// a predicate is a function with signature: (x) -> boolean
const predicate = function (x) { return x>-1 || x<=5 };

// a positive number
const Rating = t.subtype(t.Num, predicate, 'Positive');

const stamp = t.struct({
    locationName: t.Str,
    geoloc:location,
    facilityName: t.Str,
    postCode:t.Str,
    FSA: t.Str,
    physicalQuality:t.maybe(Rating),
    chemicalContaminents:t.maybe(Rating),
    microbialSafety:t.maybe(Rating),
    temperatureControl:t.maybe(Rating)
});

const Passport = t.struct({
    itemId: t.Num,
    name:t.Str,
    stamps: t.list(stamp),
    links: t.list(t.Number)
});

module.exports = {
    step: step,
    Passport: Passport,
    stamp:stamp,
}<|endoftext|>


<commit_before>KityMinder.registerModule( "LayoutModule", function () {
	var defaultHeight = 25;
	//更新分支的高度信息
	var updateBranchHeight = function ( node, appendSide, root, isAdd, oldParent ) {
		var siblings = ( function () {
			if ( !isAdd ) {
				return oldParent.getChildren();
			} else if ( parent === root ) {
				return root.getData( "layer" + appendSide )[ 1 ];
			} else {
				return node.getParent().getChildren();
			}
		} )();
		console.log( siblings );
		if ( !isAdd && ( siblings.length === 0 || ( !oldParent.getParent() && oldParent !== root ) ) ) {
			return false;
		}
		var parent = isAdd ? node.getParent() : oldParent;
		node.setData( "branchheight", defaultHeight + 10 );
		if ( isAdd ) {
			var add = ( ( siblings.length === 1 && node.getParent() !== root ) ? 0 : ( defaultHeight + 10 ) );
			console.log( add );
			while ( parent || ( parent === root ) ) {
				var branchheight = parent.getData( appendSide + "Height" ) || parent.getData( "branchheight" ) || 0;
				if ( parent === root ) {
					parent.setData( appendSide + "Height", branchheight + add );
				} else {
					parent.setData( "branchheight", branchheight + add );
				}
				parent = parent.getParent();
			}

			if ( siblings.length === 1 ) {
				return false;
			} else {
				return true;
			}
		} else {
			var dec = node.getData( "branchheight" );
			do {
				var branchheight2 = parent.getData( appendSide + "Height" ) || parent.getData( "branchheight" ) || 0;
				if ( parent === root ) {
					parent.setData( appendSide + "Height", branchheight2 - dec );
				} else {
					parent.setData( "branchheight", branchheight2 - dec );
				}
				parent = parent.getParent();
			} while ( parent );
			return true;
		}
	};
	var reAnalyze = function ( km, layerArray, appendSide ) {
		for ( var lv = 0; lv < layerArray.length; lv++ ) {
			var lvData = layerArray[ lv ];
			for ( var i = 0; i < lvData.length; i++ ) {
				var children = ( lv === 0 ? layerArray[ 1 ] : lvData[ i ].getChildren() );
				if ( !children || children.length === 0 ) continue;
				var branchheight = lvData[ i ].getData( appendSide + "Height" ) || lvData[ i ].getData( "branchheight" );
				var sY = lvData[ i ].getData( "y" ) + ( children[ 0 ].getData( "branchheight" ) - branchheight ) / 2;
				for ( var j = 0; j < children.length; j++ ) {
					children[ j ].setData( "y", sY );
					var part1 = ( children[ j ].getData( "branchheight" ) - 10 ) / 2 + 10;
					var part2 = ( children[ j + 1 ] ? ( children[ j + 1 ].getData( "branchheight" ) - 10 ) / 2 : 0 );
					sY += ( part1 + part2 );
				}
				km.execCommand( "rendernode", children );
			}
		}
	};
	var createChildNode = function ( km, parent, index ) {
		var root = km.getRoot();
		var appendSide = parent.getData( "appendside" );
		var _node = new MinderNode();
		_node.setData( "branchheight", 0 );
		parent.insertChild( _node, index );

		_node.setData( "appendside", appendSide );
		if ( parent === root ) {
			var sidecount = root.getData( "sidecount" );
			if ( sidecount + 1 === 5 ) {
				root.setData( "sidecount", 0 );
				root.setData( "appendside", ( "leftright" ).replace( appendSide, "" ) );
			} else {
				root.setData( "sidecount", sidecount + 1 );
			}
		}
		var parentX = parent.getData( "x" );
		var parentWidth = parent.getRenderContainer().getWidth();

		switch ( appendSide ) {
		case "left":
			_node.setData( "x", parentX - parentWidth - 50 );
			_node.setData( "align", "right" );
			break;
		case "right":
			_node.setData( "x", parentX + parentWidth + 50 );
			_node.setData( "align", "left" );
			break;
		default:
			break;
		}

		var layer = parent.getData( "layer" ) + 1;
		var layerArray = root.getData( "layer" + appendSide );
		layerArray[ layer ] = layerArray[ layer ] || [];
		var layerData = layerArray[ layer ];
		var insertPos = 0;
		_node.setData( "layer", layer );

		//遍历层级链
		var getIndexList = function ( node ) {
			var indexList = [];
			var parent = node;
			do {
				indexList.push( parent.getIndex() );
				parent = parent.getParent();
			} while ( parent );
			return indexList.reverse();
		};

		//比较两个层级链的大小
		var indexLarger = function ( List1, List2 ) {
			var larger = true;
			for ( var i = 0; i < List1.length; i++ ) {
				if ( List1[ i ] == List2[ i ] ) {
					continue;
				}
				if ( List1[ i ] < List2[ i ] ) {
					larger = false;
				}
				break;
			}
			return larger;
		};

		//选定合适的位置插入节点
		for ( var l = layerData.length - 1; l >= 0; l-- ) {
			var nodeIndexList = getIndexList( _node );
			if ( !indexLarger( getIndexList( layerData[ l ] ), nodeIndexList ) ) {
				insertPos = l + 1;
				break;
			}
		}

		layerData.splice( insertPos, 0, _node );
		var reAnal = updateBranchHeight( _node, appendSide, root, true );
		//判断是重绘全部还是只是添加节点
		if ( reAnal ) {
			reAnalyze( km, layerArray, appendSide );
		} else {
			_node.setData( "y", _node.getParent().getData( "y" ) );
			km.execCommand( "rendernode", _node );
		}
		return _node;
	};

	var CreateChildNodeCommand = kity.createClass( "CreateChildNodeCommand", ( function () {
		return {
			base: Command,
			execute: createChildNode
		};
	} )() );

	var CreateSiblingNodeCommand = kity.createClass( "CreateSiblingNodeCommand", ( function () {
		return {
			base: Command,
			execute: function ( km, sibling ) {
				var parent = sibling.getParent();
				var index = sibling.getIndex() + 1;
				if ( parent ) {
					return createChildNode( km, parent, index );
				} else {
					return false;
				}
			}
		};
	} )() );

	var RemoveNodeCommand = kity.createClass( "RemoveNodeCommand", ( function () {

		return {
			base: Command,
			execute: function ( km, nodes ) {
				var root = km.getRoot();
				for ( var i = 0; i < nodes.length; i++ ) {
					var parent = nodes[ i ].getParent();
					if ( parent ) {
						var appendSide = nodes[ i ].getData( "appendside" );
						var layer = nodes[ i ].getData( "layer" );
						parent.removeChild( nodes[ i ] );
						var layerArray = root.getData( "layer" + appendSide );
						var layerData = layerArray[ layer ];
						//移除层结构中的node
						for ( var j = 0; j < layerData.length; j++ ) {
							if ( layerData[ j ] === nodes[ i ] ) {
								layerData.splice( j, 1 );
								break;
							}
						}
						var reAnal = updateBranchHeight( nodes[ i ], appendSide, root, false, parent );
						console.log( layerArray );
						if ( reAnal ) {
							reAnalyze( km, layerArray, appendSide );
						}
					}
				}
				this.setContentChanged( true );
			}
		};
	} )() );
	return {
		"commands": {
			"createchildnode": CreateChildNodeCommand,
			"createsiblingnode": CreateSiblingNodeCommand,
			"removenode": RemoveNodeCommand
		},

		"events": {

		}
	};
} );<commit_msg>changed delete<commit_after>KityMinder.registerModule( "LayoutModule", function () {
	var defaultHeight = 25;
	//更新分支的高度信息
	var updateBranchHeight = function ( node, appendSide, root, isAdd, oldParent ) {
		var siblings = ( function () {
			if ( !isAdd ) {
				return oldParent.getChildren();
			} else if ( parent === root ) {
				return root.getData( "layer" + appendSide )[ 1 ];
			} else {
				return node.getParent().getChildren();
			}
		} )();
		var parent = isAdd ? node.getParent() : oldParent;
		node.setData( "branchheight", defaultHeight + 10 );
		if ( isAdd ) {
			var add = ( ( siblings.length === 1 && node.getParent() !== root ) ? 0 : ( defaultHeight + 10 ) );
			console.log( add );
			while ( parent || ( parent === root ) ) {
				var branchheight = parent.getData( appendSide + "Height" ) || parent.getData( "branchheight" ) || 0;
				if ( parent === root ) {
					parent.setData( appendSide + "Height", branchheight + add );
				} else {
					parent.setData( "branchheight", branchheight + add );
				}
				parent = parent.getParent();
			}

			if ( siblings.length === 1 ) {
				return false;
			} else {
				return true;
			}
		} else {
			var dec = node.getData( "branchheight" );
			do {
				var branchheight2 = parent.getData( appendSide + "Height" ) || parent.getData( "branchheight" ) || 0;
				if ( parent === root ) {
					parent.setData( appendSide + "Height", branchheight2 - dec );
				} else {
					parent.setData( "branchheight", branchheight2 - dec );
				}
				parent = parent.getParent();
			} while ( parent );
			return true;
		}
	};
	var reAnalyze = function ( km, layerArray, appendSide ) {
		for ( var lv = 0; lv < layerArray.length; lv++ ) {
			var lvData = layerArray[ lv ];
			for ( var i = 0; i < lvData.length; i++ ) {
				var children = ( lv === 0 ? layerArray[ 1 ] : lvData[ i ].getChildren() );
				if ( !children || children.length === 0 ) continue;
				var branchheight = lvData[ i ].getData( appendSide + "Height" ) || lvData[ i ].getData( "branchheight" );
				var sY = lvData[ i ].getData( "y" ) + ( children[ 0 ].getData( "branchheight" ) - branchheight ) / 2;
				for ( var j = 0; j < children.length; j++ ) {
					children[ j ].setData( "y", sY );
					var part1 = ( children[ j ].getData( "branchheight" ) - 10 ) / 2 + 10;
					var part2 = ( children[ j + 1 ] ? ( children[ j + 1 ].getData( "branchheight" ) - 10 ) / 2 : 0 );
					sY += ( part1 + part2 );
				}
				km.execCommand( "rendernode", children );
			}
		}
	};
	var createChildNode = function ( km, parent, index ) {
		var root = km.getRoot();
		var appendSide = parent.getData( "appendside" );
		var _node = new MinderNode();
		_node.setData( "branchheight", 0 );
		parent.insertChild( _node, index );

		_node.setData( "appendside", appendSide );
		if ( parent === root ) {
			var sidecount = root.getData( "sidecount" );
			if ( sidecount + 1 === 5 ) {
				root.setData( "sidecount", 0 );
				root.setData( "appendside", ( "leftright" ).replace( appendSide, "" ) );
			} else {
				root.setData( "sidecount", sidecount + 1 );
			}
		}
		var parentX = parent.getData( "x" );
		var parentWidth = parent.getRenderContainer().getWidth();

		switch ( appendSide ) {
		case "left":
			_node.setData( "x", parentX - parentWidth - 50 );
			_node.setData( "align", "right" );
			break;
		case "right":
			_node.setData( "x", parentX + parentWidth + 50 );
			_node.setData( "align", "left" );
			break;
		default:
			break;
		}

		var layer = parent.getData( "layer" ) + 1;
		var layerArray = root.getData( "layer" + appendSide );
		layerArray[ layer ] = layerArray[ layer ] || [];
		var layerData = layerArray[ layer ];
		var insertPos = 0;
		_node.setData( "layer", layer );

		//遍历层级链
		var getIndexList = function ( node ) {
			var indexList = [];
			var parent = node;
			do {
				indexList.push( parent.getIndex() );
				parent = parent.getParent();
			} while ( parent );
			return indexList.reverse();
		};

		//比较两个层级链的大小
		var indexLarger = function ( List1, List2 ) {
			var larger = true;
			for ( var i = 0; i < List1.length; i++ ) {
				if ( List1[ i ] == List2[ i ] ) {
					continue;
				}
				if ( List1[ i ] < List2[ i ] ) {
					larger = false;
				}
				break;
			}
			return larger;
		};

		//选定合适的位置插入节点
		for ( var l = layerData.length - 1; l >= 0; l-- ) {
			var nodeIndexList = getIndexList( _node );
			if ( !indexLarger( getIndexList( layerData[ l ] ), nodeIndexList ) ) {
				insertPos = l + 1;
				break;
			}
		}

		layerData.splice( insertPos, 0, _node );
		var reAnal = updateBranchHeight( _node, appendSide, root, true );
		//判断是重绘全部还是只是添加节点
		if ( reAnal ) {
			reAnalyze( km, layerArray, appendSide );
		} else {
			_node.setData( "y", _node.getParent().getData( "y" ) );
			km.execCommand( "rendernode", _node );
		}
		return _node;
	};

	var CreateChildNodeCommand = kity.createClass( "CreateChildNodeCommand", ( function () {
		return {
			base: Command,
			execute: createChildNode
		};
	} )() );

	var CreateSiblingNodeCommand = kity.createClass( "CreateSiblingNodeCommand", ( function () {
		return {
			base: Command,
			execute: function ( km, sibling ) {
				var parent = sibling.getParent();
				var index = sibling.getIndex() + 1;
				if ( parent ) {
					return createChildNode( km, parent, index );
				} else {
					return false;
				}
			}
		};
	} )() );

	var RemoveNodeCommand = kity.createClass( "RemoveNodeCommand", ( function () {

		return {
			base: Command,
			execute: function ( km, nodes ) {
				var root = km.getRoot();
				for ( var i = 0; i < nodes.length; i++ ) {
					var parent = nodes[ i ].getParent();
					if ( parent ) {
						var appendSide = nodes[ i ].getData( "appendside" );
						var layer = nodes[ i ].getData( "layer" );
						parent.removeChild( nodes[ i ] );
						var layerArray = root.getData( "layer" + appendSide );
						var layerData = layerArray[ layer ];
						//移除层结构中的node
						for ( var j = 0; j < layerData.length; j++ ) {
							if ( layerData[ j ] === nodes[ i ] ) {
								layerData.splice( j, 1 );
								break;
							}
						}
						var reAnal = updateBranchHeight( nodes[ i ], appendSide, root, false, parent );
						console.log( layerArray );
						if ( reAnal ) {
							reAnalyze( km, layerArray, appendSide );
						}
					}
				}
				this.setContentChanged( true );
			}
		};
	} )() );
	return {
		"commands": {
			"createchildnode": CreateChildNodeCommand,
			"createsiblingnode": CreateSiblingNodeCommand,
			"removenode": RemoveNodeCommand
		},

		"events": {

		}
	};
} );<|endoftext|>