<commit_before>/**
 * Module dependencies
 */

var path = require('path');
var fs = require('fs');
var _ = require('@sailshq/lodash');
var chalk = require('chalk');
var COMMON_JS_FILE_EXTENSIONS = require('common-js-file-extensions');
var flaverr = require('flaverr');
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Note that `whelk`, `machinepack-process`, and `../lib/app` are
// conditionally required below, only in the cases where they are actually used.
// (That way you don't have to wait for them to load if you're not using them.)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

/**
 * Module constants
 */

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Supported file extensions for imperative code files such as hooks:
//  • 'js' (.js)
//  • 'ts' (.ts)
//  • 'es6' (.es6)
//  • ...etc.
//
// > For full list, see:
// > https://github.com/luislobo/common-js-file-extensions/blob/210fd15d89690c7aaa35dba35478cb91c693dfa8/README.md#code-file-extensions
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
var BASIC_SUPPORTED_FILE_EXTENSIONS = COMMON_JS_FILE_EXTENSIONS.code;

/**
 * `sails run`
 *
 * Run a script for the Sails app in the current working directory.
 *
 * This matches either a JavaScript file in the `scripts/` directory, or one of the command-line scripts
 * declared within the `scripts: {}` dictionary in the package.json file.
 *
 * @see https://sailsjs.com/documentation/reference/command-line-interface/sails-run
 */

module.exports = function(scriptName) {

  // If there is only one argument, it means there is actually no scriptName at all.
  // (A detail of how commander works.)
  if (arguments.length === 1) {
    scriptName = undefined;
  }

  // Sanitize the script name, for comfort.
  if (!scriptName) {
    console.error('Which one?  (To run a script, provide its name.)');
    console.error('For example:');
    console.error('    sails run add-customer');
    console.error();
    console.error('^ runs `scripts/add-customer.js`.');
    console.error();
    console.error('(For more help, visit '+chalk.underline('http://sailsjs.com/support')+'.)');
    return process.exit(1);
  }

  scriptName = _.trim(scriptName);
  scriptName = scriptName.replace(/^scripts\//, '');
  if (scriptName.match(/\//)) {
    console.error('Cannot run `'+scriptName+'`.  Script name should never contain any slashes.');
    return process.exit(1);
  }//-•

  // Examine the script name and determine if it has a file extension included.
  // If so, we'll rip it out of the script name, but keep a reference to it.
  // Otherwise, we'll always assume that we're looking for a normal `.js` file.
  var X_BASIC_SUPPORTED_FILE_EXTENSION = new RegExp('^([^.]+)\\.(' + BASIC_SUPPORTED_FILE_EXTENSIONS.join('|') + ')$');
  var matchedFileExtension = scriptName.match(X_BASIC_SUPPORTED_FILE_EXTENSION);
  var fileExtension;
  if (matchedFileExtension) {
    fileExtension = matchedFileExtension[2];
    scriptName = scriptName.replace(X_BASIC_SUPPORTED_FILE_EXTENSION, '$1');
  }
  else {
    fileExtension = 'js';
  }

  // console.log(scriptName);
  // console.log(fileExtension);
  // return;

  // First, we need to determine the appropriate script to run.
  // (either a terminal command or a specially-formatted Node.js/Sails.js module)

  // We begin by figuring out whether this is a command-line script or a script (MaS) definition.
  var commandToRun;

  // Check the package.json file.
  try {
    var pathToLocalPackageJson = path.resolve(process.cwd(), 'package.json');
    var packageJson;
    try {
      packageJson = require(pathToLocalPackageJson);
    } catch (e) {
      switch (e.code) {
        case 'MODULE_NOT_FOUND': throw flaverr('E_NO_PACKAGE_JSON', new Error('No package.json file.  Are you sure you\'re in the root directory of a Node.js/Sails.js app?'));
        default: throw e;
      }
    }

    if (!_.isUndefined(packageJson.scripts) && (!_.isObject(packageJson.scripts) || _.isArray(packageJson.scripts))) {
      throw flaverr('E_MALFORMED_PACKAGE_JSON', new Error('This package.json file has an invalid `scripts` property -- should be a dictionary (plain JS object).'));
    }

    commandToRun = packageJson.scripts[scriptName];

  } catch (e) {
    switch (e.code) {
      case 'E_NO_PACKAGE_JSON':
      case 'E_MALFORMED_PACKAGE_JSON':
        console.error('--');
        console.error(chalk.red(e.message));
        return process.exit(1);

      default:
        console.error('--');
        console.error(chalk.bold('Oops, something unexpected happened:'));
        console.error(chalk.red(e.stack));
        console.error('--');
        console.error('Please read the error message above and troubleshoot accordingly.');
        console.error('(You can report suspected bugs at '+chalk.underline('http://sailsjs.com/bugs')+'.)');
        return process.exit(1);
    }
  }

  // Now check the `scripts/` directory to see if the file exists.
  var relativePathToScript = 'scripts/'+scriptName+'.'+fileExtension;
  var doesScriptFileExist = fs.existsSync(path.resolve(relativePathToScript));

  // Ensure that this script is not defined in BOTH places.
  if (commandToRun && doesScriptFileExist) {
    console.error('Cannot run `'+scriptName+'` because it is too ambiguous.');
    console.error('A script should only be defined once, but that script is defined in both the package.json file');
    console.error('AND as a file in the `scripts/` directory.');
    return process.exit(1);
  }

  // Ensure that this script exists one place or the other.
  if (!commandToRun && !doesScriptFileExist) {
    console.error('Unknown script: `'+scriptName+'`');
    console.error('No matching script is defined at `'+relativePathToScript+'`.');
    console.error('(And there is no matching NPM script in the package.json file.)');
    return process.exit(1);
  }

  // If this is a Node.js/Sails.js script (machine def), then require the script file
  // to get the module definition, then run it using MaS.
  if (!commandToRun) {
    try {
      var pathToScriptDef = path.resolve(process.cwd(), 'scripts/'+scriptName);
      var scriptDef;
      try {
        scriptDef = require(pathToScriptDef);
      } catch (e) {
        switch (e.code) {
          case 'MODULE_NOT_FOUND': throw flaverr('E_FAILED_TO_REQUIRE_SCRIPT_DEF', new Error('Encountered an error while loading the script definition.  Are you sure this is a well-formed Node.js/Sails.js script definition?  Error details:\n'+e.stack));
          default: throw e;
        }
      }

      // Make sure the script is at least basically valid.
      // (MaS will check it more later -- this is just preliminary -- and also to make sure that it's not `{}`,
      // the special indicator that the script definition didn't export _ANYTHING_ at all.)
      if (!_.isObject(scriptDef) || _.isArray(scriptDef) || _.isEqual(scriptDef, {})) {
        console.error('');
        console.error('');
        console.error('Invalid script: `'+scriptName+'`');
        console.error('');
        console.error('A well-formed Node.js/Sails.js script should export a script definition.');
        console.error('In other words, it should be defined more or less like this:');
        console.error('');
        console.error('    ```````````````````````````````````````````````````````````');
        console.error('    module.exports = {');
        console.error('      description: \'Do a thing given some stuff.\',');
        console.error('      inputs: {');
        console.error('        someStuff: { type: \'string\', required: true }');
        console.error('      },');
        console.error('      fn: async function (inputs, exits) {');
        console.error('        // ...');
        console.error('        sails.log(\'Hello world!\');');
        console.error('        return exits.success();');
        console.error('      }');
        console.error('    };');
        console.error('    ```````````````````````````````````````````````````````````');
        console.error('');
        return process.exit(1);
      }

      // Modify the script definition to add `sails: require('sails')` and `habitat: 'sails'`
      // (unless it explicitly disables this behavior with `sails: false` or by explicitly
      // declaring some other habitat)
      var isLifecycleMgmtExplicitlyDisabled = (
        scriptDef.sails === false || (
          !_.isUndefined(scriptDef.habitat) && scriptDef.habitat !== 'sails'
        )
      );
      if (!isLifecycleMgmtExplicitlyDisabled) {
        // (Only require the rest of the Sails framework if it's needed.)
        var Sails = require('../lib/app');
        scriptDef.habitat = 'sails';
        scriptDef.sails = Sails();
      }

      // (Only require whelk if it's needed.)
      var whelk = require('whelk');

      // Now actually run the script.
      whelk(scriptDef);

    } catch (err) {
      console.error(err);
      return process.exit(1);
    }
  }
  // Otherwise, this is an NPM script of some kind, from the package.json file.
  else {

    // So execute the command like you would on the terminal.

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // FUTURE: Consider pulling this boilerplate setup code into spawnChildProcess() machine
    // as a way of leveraging a subshell to remove the need to pass in CLI args directly.
    // Maybe as an option at least.
    //
    // > Also, we should also consider adding a notifier function to optionally provide
    // > special instructions of what to do when the current (parent) process receives a SIGINT.
    // > (Otherwise, by default, the SIGINT behavior implemented below could be used instead.)
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    //
    // -AND/OR-
    //
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // FUTURE: Consider exposing an optional `onData` input to the more basic `executeCommand()`
    // machine.  That way, you can just pass in a notifier function that handles the child's
    // writes to its stdout and stderr streams without having to dig into all of these
    // annoying complexities.  Also, it'd then be possible to add another input: a flag that
    // allows you to choose whether or not to store output and pass it to the callback
    // (e.g. `bufferOutput`).
    //
    // > Finally, we should also consider adding the same SIGINT notifier function mentioned above.
    //
    // Here's an example of how we might put it all together:
    // ```
    // Process.executeCommand({
    //   command: commandToRun,
    //   bufferOutput: false,
    //   killOnParentSigint: false,
    //   onData: function (data, stdStreamName){
    //     process[stdStreamName].write(data);
    //   }
    // }).exec(function (err) {
    //   if (err) {
    //     console.error('Error occured running `'+ commandToRun+ '`');
    //     console.error('Please resolve any issues and try `sails run '+scriptName+'` again.');
    //     console.error('Details:');
    //     console.error(err);
    //     return process.exit(1);
    //   }//-•
    //
    //   return process.exit(0);
    // });//< Process.executeCommand().exec() > _∏_
    // ```
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    // (Only require machinepack-process if it's needed.)
    var Process = require('machinepack-process');

    // Determine an appropriate name for our shell.
    // > This is mainly just so we don't have to try and do any fancy parsing of the command,
    // > allowing for more platform-specific customization.  (Mirroring the NPM CLI here)
    var shProcName;
    var shFlag;
    if (process.platform === 'win32') {
      shProcName = process.env.comspec || 'cmd';
      shFlag = '/d /s /c';
    }
    else {
      shProcName = 'sh';
      shFlag = '-c';
    }

    var childProcess = Process.spawnChildProcess({
      command: shProcName,
      cliArgs: [ shFlag, commandToRun ]
    }).execSync();

    // Pipe output from the child process to the current (parent) process.
    childProcess.stdout.pipe(process.stdout);
    childProcess.stderr.pipe(process.stderr);

    // Set up CTRL+C listener on the parent process that will force-kill this child process.
    // (Note that we define the event listener as a named function so we can unbind it below.)
    var onSigTerm = function (){
      Process.killChildProcess({ childProcess: childProcess, force: true }).exec(function (_forceKillErr){
        if (_forceKillErr) {
          console.error('There was a problem terminating this script:\n'+_forceKillErr.stack+'\nHere are some details which might be helpful:\n' + _forceKillErr.stack);
        }
      });
    };
    process.once('SIGTERM', onSigTerm);

    var spinlocked;
    (function (proceed){

      childProcess.on('error', function (err) { return proceed(err); });
      childProcess.stderr.on('error', function (err) { return proceed(err); });
      childProcess.stdout.on('error', function (err) { return proceed(err); });
      childProcess.on('close', function (code, signal) {
        // log.silly('lifecycle', logid(pkg, stage), 'Returned: code:', code, ' signal:', signal)
        // If a signal was received, terminate the current parent process (i.e. `sails run`).
        if (signal) {
          // Note that, in this case, `proceed()` is never called.
          // (But it doesn't actually matter, because we'll have killed the process.)
          return process.kill(process.pid, signal);
        }

        // Otherwise if we got a non-zero exit code, then consider this an error.
        if (code !== 0) {
          return proceed(new Error('Exit status '+code));
        }

        // Otherwise, consider it a success.
        return proceed();
      });

    })(function(err){
      if (err) {

        if (spinlocked) {
          console.error(err);
          return;
        }
        spinlocked = true;

        console.error('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ');
        console.error('Error occured running `'+ commandToRun+ '`');
        console.error('Please resolve any issues and try `sails run '+scriptName+'` again.');
        console.error('Details:');
        console.error(err);

        process.removeListener('SIGTERM', onSigTerm);
        return process.exit(1);
      }//-•

      return process.exit(0);

    });//</ self-calling function > _∏_

  }//</ else >

};

<commit_msg>A few minor tweaks<commit_after>/**
 * Module dependencies
 */

var path = require('path');
var fs = require('fs');
var _ = require('@sailshq/lodash');
var chalk = require('chalk');
var COMMON_JS_FILE_EXTENSIONS = require('common-js-file-extensions');
var flaverr = require('flaverr');
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Note that `whelk`, `machinepack-process`, and `../lib/app` are
// conditionally required below, only in the cases where they are actually used.
// (That way you don't have to wait for them to load if you're not using them.)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

/**
 * Module constants
 */

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Supported file extensions for imperative code files such as hooks:
//  • 'js' (.js)
//  • 'ts' (.ts)
//  • 'es6' (.es6)
//  • ...etc.
//
// > For full list, see:
// > https://github.com/luislobo/common-js-file-extensions/blob/210fd15d89690c7aaa35dba35478cb91c693dfa8/README.md#code-file-extensions
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
var BASIC_SUPPORTED_FILE_EXTENSIONS = COMMON_JS_FILE_EXTENSIONS.code;

/**
 * `sails run`
 *
 * Run a script for the Sails app in the current working directory.
 *
 * This matches either a JavaScript file in the `scripts/` directory, or one of the command-line scripts
 * declared within the `scripts: {}` dictionary in the package.json file.
 *
 * @see https://sailsjs.com/documentation/reference/command-line-interface/sails-run
 */

module.exports = function(scriptName) {

  // If there is only one argument, it means there is actually no scriptName at all.
  // (A detail of how commander works.)
  if (arguments.length === 1) {
    scriptName = undefined;
  }

  // Sanitize the script name, for comfort.
  if (!scriptName) {
    console.error('Which one?  (To run a script, provide its name.)');
    console.error('For example:');
    console.error('    sails run rebuild-cloud-sdk');
    console.error();
    console.error('^ runs `scripts/rebuild-cloud-sdk.js`.');
    console.error();
    console.error('(For more help, visit '+chalk.underline('https://sailsjs.com/support')+'.)');
    return process.exit(1);
  }

  scriptName = _.trim(scriptName);
  scriptName = scriptName.replace(/^scripts\//, '');
  if (scriptName.match(/\//)) {
    console.error('Cannot run `'+scriptName+'`.  Script name should never contain any slashes.');
    return process.exit(1);
  }//-•

  // Examine the script name and determine if it has a file extension included.
  // If so, we'll rip it out of the script name, but keep a reference to it.
  // Otherwise, we'll always assume that we're looking for a normal `.js` file.
  var X_BASIC_SUPPORTED_FILE_EXTENSION = new RegExp('^([^.]+)\\.(' + BASIC_SUPPORTED_FILE_EXTENSIONS.join('|') + ')$');
  var matchedFileExtension = scriptName.match(X_BASIC_SUPPORTED_FILE_EXTENSION);
  var fileExtension;
  if (matchedFileExtension) {
    fileExtension = matchedFileExtension[2];
    scriptName = scriptName.replace(X_BASIC_SUPPORTED_FILE_EXTENSION, '$1');
  }
  else {
    fileExtension = 'js';
  }

  // First, we need to determine the appropriate script to run.
  // (either a terminal command or a specially-formatted Node.js/Sails.js module)

  // We begin by figuring out whether this is a script from the package.json
  // or a definition in the `scripts/` folder.
  var pjCommandToRun;

  // Check the package.json file.
  try {
    var pathToLocalPj = path.resolve(process.cwd(), 'package.json');
    var packageJson;
    try {
      packageJson = require(pathToLocalPj);
    } catch (e) {
      switch (e.code) {
        case 'MODULE_NOT_FOUND': throw flaverr('E_NO_PACKAGE_JSON', new Error('No package.json file.  Are you sure you\'re in the root directory of a Node.js/Sails.js app?'));
        default: throw e;
      }
    }

    if (!_.isUndefined(packageJson.scripts) && (!_.isObject(packageJson.scripts) || _.isArray(packageJson.scripts))) {
      throw flaverr('E_MALFORMED_PACKAGE_JSON', new Error('This package.json file has an invalid `scripts` property -- should be a dictionary (plain JS object).'));
    }

    pjCommandToRun = packageJson.scripts[scriptName];

  } catch (e) {
    switch (e.code) {
      case 'E_NO_PACKAGE_JSON':
      case 'E_MALFORMED_PACKAGE_JSON':
        console.error('--');
        console.error(chalk.red(e.message));
        return process.exit(1);

      default:
        console.error('--');
        console.error(chalk.bold('Oops, something unexpected happened:'));
        console.error(chalk.red(e.stack));
        console.error('--');
        console.error('Please read the error message above and troubleshoot accordingly.');
        console.error('(You can report suspected bugs at '+chalk.underline('http://sailsjs.com/bugs')+'.)');
        return process.exit(1);
    }
  }

  // Now check the `scripts/` directory to see if the file exists.
  var relativePathToScript = 'scripts/'+scriptName+'.'+fileExtension;
  var doesScriptFileExist = fs.existsSync(path.resolve(relativePathToScript));

  // Ensure that this script is not defined in BOTH places.
  if (pjCommandToRun && doesScriptFileExist) {
    console.error('Cannot run `'+scriptName+'` because it is too ambiguous.');
    console.error('A script should only be defined once, but that script is defined in both the package.json file');
    console.error('AND as a file in the `scripts/` directory.');
    return process.exit(1);
  }

  // Ensure that this script exists one place or the other.
  if (!pjCommandToRun && !doesScriptFileExist) {
    console.error('Unknown script: `'+scriptName+'`');
    console.error('No matching script is defined at `'+relativePathToScript+'`.');
    console.error('(And there is no matching NPM script in the package.json file.)');
    return process.exit(1);
  }

  // If this is a Node.js/Sails.js script (machine def), then require the script file
  // to get the module definition, then run it using MaS.
  if (!pjCommandToRun) {
    try {
      var pathToScriptDef = path.resolve(process.cwd(), 'scripts/'+scriptName);
      var scriptDef;
      try {
        scriptDef = require(pathToScriptDef);
      } catch (e) {
        switch (e.code) {
          case 'MODULE_NOT_FOUND': throw flaverr('E_FAILED_TO_REQUIRE_SCRIPT_DEF', new Error('Encountered an error while loading the script definition.  Are you sure this is a well-formed Node.js/Sails.js script definition?  Error details:\n'+e.stack));
          default: throw e;
        }
      }

      // Make sure the script is at least basically valid.
      // (MaS will check it more later -- this is just preliminary -- and also to make sure that it's not `{}`,
      // the special indicator that the script definition didn't export _ANYTHING_ at all.)
      if (!_.isObject(scriptDef) || _.isArray(scriptDef) || _.isEqual(scriptDef, {})) {
        console.error('');
        console.error('');
        console.error('Invalid script: `'+scriptName+'`');
        console.error('');
        console.error('A well-formed Node.js/Sails.js script should export a script definition.');
        console.error('In other words, it should be defined more or less like this:');
        console.error('');
        console.error('    ```````````````````````````````````````````````````````````');
        console.error('    module.exports = {');
        console.error('      description: \'Do a thing given some stuff.\',');
        console.error('      inputs: {');
        console.error('        someStuff: { type: \'string\', required: true }');
        console.error('      },');
        console.error('      fn: async function (inputs, exits) {');
        console.error('        // ...');
        console.error('        sails.log(\'Hello world!\');');
        console.error('        return exits.success();');
        console.error('      }');
        console.error('    };');
        console.error('    ```````````````````````````````````````````````````````````');
        console.error('');
        return process.exit(1);
      }

      // Modify the script definition to add `sails: require('sails')` and `habitat: 'sails'`
      // (unless it explicitly disables this behavior with `sails: false` or by explicitly
      // declaring some other habitat)
      var isLifecycleMgmtExplicitlyDisabled = (
        scriptDef.sails === false || (
          !_.isUndefined(scriptDef.habitat) && scriptDef.habitat !== 'sails'
        )
      );
      if (!isLifecycleMgmtExplicitlyDisabled) {
        // (Only require the rest of the Sails framework if it's needed.)
        var Sails = require('../lib/app');
        scriptDef.habitat = 'sails';
        scriptDef.sails = Sails();
      }

      // (Only require whelk if it's needed.)
      var whelk = require('whelk');

      // Now actually run the script.
      whelk(scriptDef);

    } catch (err) {
      console.error(err);
      return process.exit(1);
    }
  }
  // Otherwise, this is an NPM script of some kind, from the package.json file.
  else {

    // So execute the command like you would on the terminal.

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // FUTURE: Consider pulling this boilerplate setup code into spawnChildProcess() machine
    // as a way of leveraging a subshell to remove the need to pass in CLI args directly.
    // Maybe as an option at least.
    //
    // > Also, we should also consider adding a notifier function to optionally provide
    // > special instructions of what to do when the current (parent) process receives a SIGINT.
    // > (Otherwise, by default, the SIGINT behavior implemented below could be used instead.)
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    //
    // -AND/OR-
    //
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // FUTURE: Consider exposing an optional `onData` input to the more basic `executeCommand()`
    // machine.  That way, you can just pass in a notifier function that handles the child's
    // writes to its stdout and stderr streams without having to dig into all of these
    // annoying complexities.  Also, it'd then be possible to add another input: a flag that
    // allows you to choose whether or not to store output and pass it to the callback
    // (e.g. `bufferOutput`).
    //
    // > Finally, we should also consider adding the same SIGINT notifier function mentioned above.
    //
    // Here's an example of how we might put it all together:
    // ```
    // Process.executeCommand({
    //   command: pjCommandToRun,
    //   bufferOutput: false,
    //   killOnParentSigint: false,
    //   onData: function (data, stdStreamName){
    //     process[stdStreamName].write(data);
    //   }
    // }).exec(function (err) {
    //   if (err) {
    //     console.error('Error occured running `'+ pjCommandToRun+ '`');
    //     console.error('Please resolve any issues and try `sails run '+scriptName+'` again.');
    //     console.error('Details:');
    //     console.error(err);
    //     return process.exit(1);
    //   }//-•
    //
    //   return process.exit(0);
    // });//< Process.executeCommand().exec() > _∏_
    // ```
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    // (Only require machinepack-process if it's needed.)
    var Process = require('machinepack-process');

    // Determine an appropriate name for our shell.
    // > This is mainly just so we don't have to try and do any fancy parsing of the command,
    // > allowing for more platform-specific customization.  (Mirroring the NPM CLI here)
    var shProcName;
    var shFlag;
    if (process.platform === 'win32') {
      shProcName = process.env.comspec || 'cmd';
      shFlag = '/d /s /c';
    }
    else {
      shProcName = 'sh';
      shFlag = '-c';
    }

    var childProcess = Process.spawnChildProcess({
      command: shProcName,
      cliArgs: [ shFlag, pjCommandToRun ]
    }).execSync();

    // Pipe output from the child process to the current (parent) process.
    childProcess.stdout.pipe(process.stdout);
    childProcess.stderr.pipe(process.stderr);

    // Set up CTRL+C listener on the parent process that will force-kill this child process.
    // (Note that we define the event listener as a named function so we can unbind it below.)
    var onSigTerm = function (){
      Process.killChildProcess({ childProcess: childProcess, force: true }).exec(function (_forceKillErr){
        if (_forceKillErr) {
          console.error('There was a problem terminating this script:\n'+_forceKillErr.stack+'\nHere are some details which might be helpful:\n' + _forceKillErr.stack);
        }
      });
    };
    process.once('SIGTERM', onSigTerm);

    var spinlocked;
    (function (proceed){

      childProcess.on('error', function (err) { return proceed(err); });
      childProcess.stderr.on('error', function (err) { return proceed(err); });
      childProcess.stdout.on('error', function (err) { return proceed(err); });
      childProcess.on('close', function (code, signal) {
        // log.silly('lifecycle', logid(pkg, stage), 'Returned: code:', code, ' signal:', signal)
        // If a signal was received, terminate the current parent process (i.e. `sails run`).
        if (signal) {
          // Note that, in this case, `proceed()` is never called.
          // (But it doesn't actually matter, because we'll have killed the process.)
          return process.kill(process.pid, signal);
        }

        // Otherwise if we got a non-zero exit code, then consider this an error.
        if (code !== 0) {
          return proceed(new Error('Exit status '+code));
        }

        // Otherwise, consider it a success.
        return proceed();
      });

    })(function(err){
      if (err) {

        if (spinlocked) {
          console.error(err);
          return;
        }
        spinlocked = true;

        console.error('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ');
        console.error('Error occured running `'+ pjCommandToRun+ '`');
        console.error('Please resolve any issues and try `sails run '+scriptName+'` again.');
        console.error('Details:');
        console.error(err);

        process.removeListener('SIGTERM', onSigTerm);
        return process.exit(1);
      }//-•

      return process.exit(0);

    });//_∏_  (†)

  }//</ else >

};

<|endoftext|>


<commit_before>function CanvasFS(cfsEl) {

    cfsEl.cfsSetData = function(d) {
        if (!(d instanceof Uint8ClampedArray)) {
            console.error('cfsSetData() passed something other than string or Uint8ClampedArray');
        }
        var ctx = this.getContext('2d');
        var s = Math.ceil(Math.sqrt(d.byteLength / 4));
        console.log('cfsSetData() using square side length %d', s);
        this.setAttribute('width', s);
        this.setAttribute('height', s);
        var idata = ctx.createImageData(s, s);
        idata.data.set(d);
        ctx.putImageData(idata, 0, 0);
        return idata;
    };

    cfsEl.cfsGetData = function() {
        var ctx = this.getContext('2d');
        var idata = ctx.getImageData(0, 0, this.width, this.height);
        var raw = idata.data;
        var arr = new Array();
        for (var i = 3 ; i < raw.length ; i += 4) {
            if (raw[i] == 0) {  //bail when alpha value is zero
                i = raw.length + 1;
            } else {
                for (var j = 0 ; j < 3 ; j++) {
                    arr.push(raw[i - 3 + j]);
                }
            }
        }
        return new Uint8ClampedArray(arr);
    };

    //this uses a two-byte length encoding in first two bytes... sorry if you want longer. :)
    cfsEl.cfsSetSteg = function(d) {
        if (!(d instanceof Uint8ClampedArray)) {
            console.error('cfsSetSteg() passed something other than string or Uint8ClampedArray');
        }
        var ctx = this.getContext('2d');
        var idata = ctx.getImageData(0, 0, this.width, this.height);
        var id = 0;
        for (var i = -2 ; i < d.length; i++) {
            for (var b = 7 ; b >= 0 ; b--) {
                if (id >= idata.data.length) {
                    console.warn('cfsSetSteg(): ran out of space in image, truncated input at i=' + i);
                    ctx.putImageData(idata, 0, 0);
                    return i;
                } else {
                    var by;
                    if (i == -2) {
                        by = d.length >> 8;
                    } else if (i == -1) {
                        by = d.length & 0x00FF;
                    } else {
                        by = d[i];
                    }
                    if (by & (1 << b)) {
                        idata.data[id] = idata.data[id] | 1;
                    } else {
                        idata.data[id] = idata.data[id] & 0xFE;
                    }
                    //console.info('d[%d] => %d   %d.%d => %d', i, by, id, b, idata.data[id]);
                    id++;
                    if (id % 4 == 3) id++;  //skip alpha
                }
            }
        }
        ctx.putImageData(idata, 0, 0);
        console.info('cfsSetSteg() wrote %d bytes into %d bytes of imagedata', d.length, id);
        return d.length;
    };

    cfsEl.cfsGetSteg = function() {
        var arr = new Array()
        var len = 0;
        var ctx = this.getContext('2d');
        var idata = ctx.getImageData(0, 0, this.width, this.height);
        var raw = idata.data;
        var b = 7;
        var by = 0;
        var byteCount = -2;
        for (var i = 0 ; i < raw.length ; i++) {
            if ((byteCount > 0) && (byteCount > len - 1)) {
                console.info('cfsGetSteg() successfully reached len=%d', len);
                //console.info('reached len=%d, arr => %o', len, arr);
                return new Uint8ClampedArray(arr);
            }
            if (i % 4 == 3) continue;
            by = by | ((raw[i] & 1) << b);
            //console.info('[%i>%i] by[%d/%d]=%o (raw[i] & 1 = %o)', i, raw[i], byteCount, len, by, (raw[i] & 1));
            b--;
            if (b < 0) {
                //console.log('[%d/%d] got all bits to make by=%o', byteCount, len, by);
                if (byteCount == -2) {
                    len = by << 8;
                    console.info('  len[0] -> %d', len);
                } else if (byteCount == -1) {
                    len = len | by;
                    console.info('  len[1] -> %d', len);
                } else {
                    arr.push(by);
                }
                by = 0;
                b = 7;
                byteCount++;
            }
        }
        console.warn('cfsGetSteg() fell thru to bottom of cfsGetSteg(); possible weird length problem');
        return new Uint8ClampedArray(arr);
    };

///////// some utilities (mostly string conversion)

/* note, there are better (utf8) solutions here: http://stackoverflow.com/q/6965107 (just too lazy to do now) */

    cfsEl.cfsStringToArr = function(str, padAlpha) {
        var a = new Array();
        var len = str.length;
        if (len % 3) len += (3 - len % 3);
        for (var i = 0 ; i < len ; i++) {
            if (i < str.length) {
                a.push(str.charCodeAt(i));
            } else {
                a.push(0);
            }
            if (padAlpha && (i % 3 == 2)) a.push(255);  // alpha value
        }
        return new Uint8ClampedArray(a);
    };

    cfsEl.cfsArrToString = function(buf) {
        return String.fromCharCode.apply(null, new Uint8ClampedArray(buf));
    };

}

<commit_msg>explanation of pending bug<commit_after>function CanvasFS(cfsEl) {

/* note: cfsSetData currently sets the data *expecting it to already have been padded out to skip A in the RGBA sets!*
   this is a horrible flaw... which i need to fix.  was just a quick way to test the data as it came out of strToArr...
   i will refactor soon! TODO  */
    cfsEl.cfsSetData = function(d) {
        if (!(d instanceof Uint8ClampedArray)) {
            console.error('cfsSetData() passed something other than string or Uint8ClampedArray');
        }
        var ctx = this.getContext('2d');
        var s = Math.ceil(Math.sqrt(d.byteLength / 4));
        console.log('cfsSetData() using square side length %d', s);
        this.setAttribute('width', s);
        this.setAttribute('height', s);
        var idata = ctx.createImageData(s, s);
        idata.data.set(d);
        ctx.putImageData(idata, 0, 0);
        return idata;
    };

    cfsEl.cfsGetData = function() {
        var ctx = this.getContext('2d');
        var idata = ctx.getImageData(0, 0, this.width, this.height);
        var raw = idata.data;
        var arr = new Array();
        for (var i = 3 ; i < raw.length ; i += 4) {
            if (raw[i] == 0) {  //bail when alpha value is zero
                i = raw.length + 1;
            } else {
                for (var j = 0 ; j < 3 ; j++) {
                    arr.push(raw[i - 3 + j]);
                }
            }
        }
        return new Uint8ClampedArray(arr);
    };

    //this uses a two-byte length encoding in first two bytes... sorry if you want longer. :)
    cfsEl.cfsSetSteg = function(d) {
        if (!(d instanceof Uint8ClampedArray)) {
            console.error('cfsSetSteg() passed something other than string or Uint8ClampedArray');
        }
        var ctx = this.getContext('2d');
        var idata = ctx.getImageData(0, 0, this.width, this.height);
        var id = 0;
        for (var i = -2 ; i < d.length; i++) {
            for (var b = 7 ; b >= 0 ; b--) {
                if (id >= idata.data.length) {
                    console.warn('cfsSetSteg(): ran out of space in image, truncated input at i=' + i);
                    ctx.putImageData(idata, 0, 0);
                    return i;
                } else {
                    var by;
                    if (i == -2) {
                        by = d.length >> 8;
                    } else if (i == -1) {
                        by = d.length & 0x00FF;
                    } else {
                        by = d[i];
                    }
                    if (by & (1 << b)) {
                        idata.data[id] = idata.data[id] | 1;
                    } else {
                        idata.data[id] = idata.data[id] & 0xFE;
                    }
                    //console.info('d[%d] => %d   %d.%d => %d', i, by, id, b, idata.data[id]);
                    id++;
                    if (id % 4 == 3) id++;  //skip alpha
                }
            }
        }
        ctx.putImageData(idata, 0, 0);
        console.info('cfsSetSteg() wrote %d bytes into %d bytes of imagedata', d.length, id);
        return d.length;
    };

    cfsEl.cfsGetSteg = function() {
        var arr = new Array()
        var len = 0;
        var ctx = this.getContext('2d');
        var idata = ctx.getImageData(0, 0, this.width, this.height);
        var raw = idata.data;
        var b = 7;
        var by = 0;
        var byteCount = -2;
        for (var i = 0 ; i < raw.length ; i++) {
            if ((byteCount > 0) && (byteCount > len - 1)) {
                console.info('cfsGetSteg() successfully reached len=%d', len);
                //console.info('reached len=%d, arr => %o', len, arr);
                return new Uint8ClampedArray(arr);
            }
            if (i % 4 == 3) continue;
            by = by | ((raw[i] & 1) << b);
            //console.info('[%i>%i] by[%d/%d]=%o (raw[i] & 1 = %o)', i, raw[i], byteCount, len, by, (raw[i] & 1));
            b--;
            if (b < 0) {
                //console.log('[%d/%d] got all bits to make by=%o', byteCount, len, by);
                if (byteCount == -2) {
                    len = by << 8;
                    console.info('  len[0] -> %d', len);
                } else if (byteCount == -1) {
                    len = len | by;
                    console.info('  len[1] -> %d', len);
                } else {
                    arr.push(by);
                }
                by = 0;
                b = 7;
                byteCount++;
            }
        }
        console.warn('cfsGetSteg() fell thru to bottom of cfsGetSteg(); possible weird length problem');
        return new Uint8ClampedArray(arr);
    };

///////// some utilities (mostly string conversion)

/* note, there are better (utf8) solutions here: http://stackoverflow.com/q/6965107 (just too lazy to do now) */

    cfsEl.cfsStringToArr = function(str, padAlpha) {
        var a = new Array();
        var len = str.length;
        if (len % 3) len += (3 - len % 3);
        for (var i = 0 ; i < len ; i++) {
            if (i < str.length) {
                a.push(str.charCodeAt(i));
            } else {
                a.push(0);
            }
            if (padAlpha && (i % 3 == 2)) a.push(255);  // alpha value
        }
        return new Uint8ClampedArray(a);
    };

    cfsEl.cfsArrToString = function(buf) {
        return String.fromCharCode.apply(null, new Uint8ClampedArray(buf));
    };

}

<|endoftext|>


<commit_before>/*
License information: MIT License

Copyright (c) Chris Schalick 2015 All Rights Reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Tree structure code creates an object hierarchy on demand
inside an HTML table, allows click to expand / collapse
to view and traverse the hierarchy.
*/

var abctree_style = document.createElement("style");
abctree_style.type = "text/css";
abctree_style.innerHTML = ".abctree_leaf { background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AMfEi8WbCB2GQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAYElEQVQY032QuQ2AMBAEZxE5ZVERufshpwQ6cAFUQEy0BLYlm8cjbbY3dzqRsc0Xkhhygx4qpV4tmdZW/2QE4ATNC0xHx7c73WVDCNhuktZd1UCMP6bNEPwylOjvgvpvNwXXOMpWayahAAAAAElFTkSuQmCC\"); width: 9px; height: 9px; float: left; margin: 3px; }";
document.getElementsByTagName("head")[0].appendChild(abctree_style);
abctree_style = document.createElement("style");
abctree_style.type = "text/css";
abctree_style.innerHTML = ".abctree_expanded { background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAIAAABv85FHAAAAT0lEQVQImWNowA0YGhoarn7+j4kQcq9//n/98//bX//f/Pz/5uf/17+Q5N78/P/2FwpCyDG6VSEjFLlPv3Hb9/UPOkKR+/EXKgphQOVwAQAPSLGYw3tZHAAAAABJRU5ErkJggg==\"); width: 9px; height: 9px; float: left; margin: 3px; }";
document.getElementsByTagName("head")[0].appendChild(abctree_style);
abctree_style = document.createElement("style");
abctree_style.type = "text/css";
abctree_style.innerHTML = ".abctree_collapsed { background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAIAAABv85FHAAAAXElEQVQImXXNQQrAIAwEQP1cHuUpn/QVxksl0FjL9qBQpXXZw8IE4ngfx8yx4NvXkiEZPAUxiCHVycSQKzyFWJAr8myewtzFjgv94uefNmgb1vdi5w1tiGWMYbs8uiCoqOdNhIkAAAAASUVORK5CYII=\"); width: 9px; height: 9px; float: left; margin: 3px; }";
document.getElementsByTagName("head")[0].appendChild(abctree_style);
abctree_style = document.createElement("style");
abctree_style.type = "text/css";
abctree_style.innerHTML = ".abctree_selected { background-color: #e0e0e0; cursor: pointer; font-family: 'Arial'; font-size: 14px; }";
document.getElementsByTagName("head")[0].appendChild(abctree_style);
abctree_style = document.createElement("style");
abctree_style.type = "text/css";
abctree_style.innerHTML = ".abctree_deselected { background-color: null; cursor: pointer; font-family: 'Arial'; font-size: 14px; }";
document.getElementsByTagName("head")[0].appendChild(abctree_style);

// abctree = root of the tree = table
var abctree = function(id, parent_id){
  "use strict";
  this.node_num = 0;
  this.id = id;
  this.nodes = [];
  this.indent = 0;
  this.table = document.createElement("table");
  this.table.id = id;
  this.selected = null;
  this.root = this;

  // insert the html element into the DOM
  document.getElementById(parent_id).appendChild(this.table);

  // return a pointer to the tree for manipulation and traversal
  return this;
};

// add a node at the top level of the tree
abctree.prototype.add_child = function(id, val, user_cb, after){
  "use strict";
  var kid = new abctree_node(this, id, val);
  this.nodes.push(kid);
  kid.select();
  var sel_cb = kid.make_callback(kid.select, kid);
  var other_cb;
  if(typeof user_cb == "function")
    other_cb = kid.make_callback(user_cb, id);
  else
    other_cb = function(){};
  var cb_fn = function(){sel_cb(); other_cb();};
  kid.table_row.children[1].onclick = cb_fn;
  return kid;
};

// get all nodes in the tree
abctree.prototype.all_below = function(){
  "use strict";
  var below = [];
  for(var x = 0; x < this.nodes.length; x++)
    below.push(this.nodes[x]);
  for(var x = 0; x < this.nodes.length; x++)
    below = below.concat(this.nodes[x].all_below());

  return below;
};

// UI asked to collapse the whole tree
abctree.prototype.collapse_all = function(item){
  "use strict";
  if(item == null)
    item = this;
  var i, nodes = item.all_below();
  for(i = 0; i < nodes.length; i++)
    nodes[i].collapse(nodes[i]);
};

// abctree_node = nodes in the tree = entries
var abctree_node = function(parent, id, val, after){
  "use strict";
  var x, new_row, l, tid, all, insert_point;
  if(typeof after == "undefined")
    after = null;
  this.root = parent.root;
  this.id = this.root.id + "." + this.root.node_num++;
  this.nodes = [];
  this.parent = parent;
  this.indent = 0;
  this.collapsed = true;
  this.table = parent.table;
  this.val = val;
  l = parent.table.rows.length;
  if(after != null){
    all = [];
    all.push(after);
    all = all.concat(after.all_below());
    tid = all[all.length - 1].id;
  }
  else if(parent.nodes.length == 0)
    tid = parent.id;
  else {
    all = parent.all_below();
    tid = all[all.length - 1].id;
  }
  insert_point = this.table.rows.length;
  for(x = 0; x < l; x++){
    if(this.table.rows[x].id == tid){
      insert_point = x + 1;
      break;
    }
  }
  new_row = this.table.insertRow(insert_point);
  new_row.style.display = "block";
  new_row.id = this.id;
  new_row.innerHTML = "

" + val + "	";
  new_row.children[0].className = "abctree_leaf";
  this.table_row = new_row;
  return this;
};

// make node invisible on page
abctree_node.prototype.hide = function(){
  "use strict";
  this.table_row.style.display = "none";
};

// make node visible on page
abctree_node.prototype.show = function(){
  "use strict";
  this.table_row.style.display = "block";
};

// user clicked on selection
abctree_node.prototype.select = function(opt){
  "use strict";
  var me;
  if(opt)
    me = opt;
  else
    me = this;
  if(me.root.selected != null)
    me.root.selected.deselect();
  me.root.selected = me;
  me.table_row.children[1].className = "abctree_selected";
};

// user clicked on selection
abctree_node.prototype.deselect = function(){
  "use strict";
  this.table_row.children[1].className = "abctree_deselected";
};

// get either all nodes below or all nodes in the
// next level down plus all nodes in expanded nodes
// beyond that
abctree_node.prototype.all_below = function(filter){
  "use strict";
  var below = [];

  for(var x = 0; x < this.nodes.length; x++){

    // add immediate children
    below.push(this.nodes[x]);

    // add children's children
    if(typeof filter == "undefined")
      below = below.concat(this.nodes[x].all_below(filter));
    else if((filter == "expanded") && (!this.nodes[x].collapsed))
      below = below.concat(this.nodes[x].all_below(filter));
  }

  return below;
};

// user clicked, collapse the tree below this node
abctree_node.prototype.collapse = function(item){
  "use strict";
  if(item.table_row.children[0].className != "abctree_leaf"){
    item.table_row.children[0].className = "abctree_collapsed";
    item.collapsed = true;
    var below = item.all_below();
    below.forEach(function(e){e.hide();});
  }
};

// user clicked, expand the tree below this node
abctree_node.prototype.expand = function(item){
  "use strict";
  if(item.table_row.children[0].className != "abctree_leaf"){
    item.table_row.children[0].className = "abctree_expanded";
    item.collapsed = false;
    var below = item.nodes;
    var below = below.concat(item.all_below("expanded"));
    below.forEach(function(e){e.show();});
  }
};

// user clicked, either expand or collapse based on state
abctree_node.prototype.toggle_expanded = function(item){
  "use strict";
  if(item.table_row.children[0].className == "abctree_expanded")
    item.collapse(item);
  else if(item.table_row.children[0].className == "abctree_collapsed")
    item.expand(item);
};

// save the instance info for later clicks
abctree_node.prototype.make_callback = function(call, arg){
  "use strict";
  var ret = function(){return call(arg);};
  return ret;
}

// add a child node beneath this one
abctree_node.prototype.add_child = function(id, val, user_cb, after){
  "use strict";
  var child = new abctree_node(this, id, val, after);
  child.indent = this.indent + 10;
  child.table_row.style.margin = "0px 0px 0px " + child.indent + "px";
  child.table_row.style.display = "none";
  child.parent = this;
  child.root = this.root;
  this.table_row.children[0].className = "abctree_collapsed";
  var sel_cb = this.make_callback(this.toggle_expanded, this);
  this.table_row.children[0].onclick = sel_cb;
  sel_cb = child.make_callback(child.select, child);
  var other_cb;
  if(typeof user_cb == "function")
    other_cb = child.make_callback(user_cb, id);
  else
    other_cb = function(){};
  var cb_fn = function(){sel_cb(); other_cb();};
  child.table_row.children[1].onclick = cb_fn;
  this.nodes.push(child);
  child.select();
  this.expand(this);
  return child;
}

// add a child node beneath this one
abctree_node.prototype.delete = function(){
  "use strict";
  var x, nodes, list = this.all_below();
  for(x = 0; x < this.table.rows.length; x++)
    if(this.table.rows[x].id == this.id){
      this.table.deleteRow(x);
      break;
    }
  for(x = 0; x < this.parent.nodes.length; x++)
    if(this.parent.nodes[x] == this){
      nodes = this.parent.nodes.slice(0, x);
      nodes = nodes.concat(this.parent.nodes.slice(x + 1));
      this.parent.nodes = nodes;
    }
  for(x = 0; x < list.length; x++)
    list[x].delete();
}

// search functions
abctree_node.prototype.get_child_by_id = function(id){
  "use strict";
  var children = this.all_below();
  for(var x = 0; x < children.length; x++)
    if(children[x].id == id)
      return children[x];

  return null;
}

abctree_node.prototype.get_child_by_val = function(val){
  "use strict";
  var children = this.all_below();
  for(var x = 0; x < children.length; x++)
    if(children[x].val == val)
      return children[x];

  return null;
}

<commit_msg>sort the object node list to make insert easier<commit_after>/*
License information: MIT License

Copyright (c) Chris Schalick 2015 All Rights Reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Tree structure code creates an object hierarchy on demand
inside an HTML table, allows click to expand / collapse
to view and traverse the hierarchy.
*/

var abctree_style = document.createElement("style");
abctree_style.type = "text/css";
abctree_style.innerHTML = ".abctree_leaf { background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AMfEi8WbCB2GQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAYElEQVQY032QuQ2AMBAEZxE5ZVERufshpwQ6cAFUQEy0BLYlm8cjbbY3dzqRsc0Xkhhygx4qpV4tmdZW/2QE4ATNC0xHx7c73WVDCNhuktZd1UCMP6bNEPwylOjvgvpvNwXXOMpWayahAAAAAElFTkSuQmCC\"); width: 9px; height: 9px; float: left; margin: 3px; }";
document.getElementsByTagName("head")[0].appendChild(abctree_style);
abctree_style = document.createElement("style");
abctree_style.type = "text/css";
abctree_style.innerHTML = ".abctree_expanded { background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAIAAABv85FHAAAAT0lEQVQImWNowA0YGhoarn7+j4kQcq9//n/98//bX//f/Pz/5uf/17+Q5N78/P/2FwpCyDG6VSEjFLlPv3Hb9/UPOkKR+/EXKgphQOVwAQAPSLGYw3tZHAAAAABJRU5ErkJggg==\"); width: 9px; height: 9px; float: left; margin: 3px; }";
document.getElementsByTagName("head")[0].appendChild(abctree_style);
abctree_style = document.createElement("style");
abctree_style.type = "text/css";
abctree_style.innerHTML = ".abctree_collapsed { background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAIAAABv85FHAAAAXElEQVQImXXNQQrAIAwEQP1cHuUpn/QVxksl0FjL9qBQpXXZw8IE4ngfx8yx4NvXkiEZPAUxiCHVycSQKzyFWJAr8myewtzFjgv94uefNmgb1vdi5w1tiGWMYbs8uiCoqOdNhIkAAAAASUVORK5CYII=\"); width: 9px; height: 9px; float: left; margin: 3px; }";
document.getElementsByTagName("head")[0].appendChild(abctree_style);
abctree_style = document.createElement("style");
abctree_style.type = "text/css";
abctree_style.innerHTML = ".abctree_selected { background-color: #e0e0e0; cursor: pointer; font-family: 'Arial'; font-size: 12px; }";
document.getElementsByTagName("head")[0].appendChild(abctree_style);
abctree_style = document.createElement("style");
abctree_style.type = "text/css";
abctree_style.innerHTML = ".abctree_deselected { background-color: null; cursor: pointer; font-family: 'Arial'; font-size: 12px; }";
document.getElementsByTagName("head")[0].appendChild(abctree_style);

// abctree = root of the tree = table
var abctree = function(id, parent_id){
  "use strict";
  this.node_num = 0;
  this.id = id;
  this.nodes = [];
  this.indent = 0;
  this.table = document.createElement("table");
  this.table.id = id;
  this.selected = null;
  this.root = this;

  // insert the html element into the DOM
  document.getElementById(parent_id).appendChild(this.table);

  // return a pointer to the tree for manipulation and traversal
  return this;
};

// add a node at the top level of the tree
abctree.prototype.add_child = function(id, val, user_cb, after){
  "use strict";
  var kid = new abctree_node(this, id, val);
  this.nodes.push(kid);
  kid.select();
  var sel_cb = kid.make_callback(kid.select, kid);
  var other_cb;
  if(typeof user_cb == "function")
    other_cb = kid.make_callback(user_cb, id);
  else
    other_cb = function(){};
  var cb_fn = function(){sel_cb(); other_cb();};
  kid.table_row.children[1].onclick = cb_fn;
  return kid;
};

// get all nodes in the tree
abctree.prototype.all_below = function(){
  "use strict";
  var below = [];
  for(var x = 0; x < this.nodes.length; x++)
    below.push(this.nodes[x]);
  for(var x = 0; x < this.nodes.length; x++)
    below = below.concat(this.nodes[x].all_below());

  return below;
};

// UI asked to collapse the whole tree
abctree.prototype.collapse_all = function(item){
  "use strict";
  if(item == null)
    item = this;
  var i, nodes = item.all_below();
  for(i = 0; i < nodes.length; i++)
    nodes[i].collapse(nodes[i]);
};

// abctree_node = nodes in the tree = entries
var abctree_node = function(parent, id, val, after){
  "use strict";
  var x, new_row, l, tid, all, insert_point;
  if(typeof after == "undefined")
    after = null;
  this.root = parent.root;
  this.id = this.root.id + "." + this.root.node_num++;
  this.nodes = [];
  this.parent = parent;
  this.indent = 0;
  this.collapsed = true;
  this.table = parent.table;
  this.val = val;
  l = parent.table.rows.length;
  tid = this.last_node_under(after).id;

/*
  if(after != null){
    all = [];
    all.push(after);
    all = all.concat(after.all_below());
    tid = all[all.length - 1].id;
  }
  else if(parent.nodes.length == 0)
    tid = parent.id;
  else {
    all = parent.all_below();
    tid = all[all.length - 1].id;
  }
*/

  insert_point = this.table.rows.length;
  for(x = 0; x < l; x++){
    if(this.table.rows[x].id == tid){
      insert_point = x + 1;
      break;
    }
  }
  new_row = this.table.insertRow(insert_point);
  new_row.style.display = "block";
  new_row.id = this.id;
  new_row.innerHTML = "

" + val + "	";
  new_row.children[0].className = "abctree_leaf";
  this.table_row = new_row;
  return this;
};

// make node invisible on page
abctree_node.prototype.hide = function(){
  "use strict";
  this.table_row.style.display = "none";
};

// make node visible on page
abctree_node.prototype.show = function(){
  "use strict";
  this.table_row.style.display = "block";
};

// user clicked on selection
abctree_node.prototype.select = function(opt){
  "use strict";
  var me;
  if(opt)
    me = opt;
  else
    me = this;
  if(me.root.selected != null)
    me.root.selected.deselect();
  me.root.selected = me;
  me.table_row.children[1].className = "abctree_selected";
};

// user clicked on selection
abctree_node.prototype.deselect = function(){
  "use strict";
  this.table_row.children[1].className = "abctree_deselected";
};

// get either all nodes below or all nodes in the
// next level down plus all nodes in expanded nodes
// beyond that
abctree_node.prototype.all_below = function(filter){
  "use strict";
  var below = [];

  for(var x = 0; x < this.nodes.length; x++){

    // add immediate children
    below.push(this.nodes[x]);

    // add children's children
    if(typeof filter == "undefined")
      below = below.concat(this.nodes[x].all_below(filter));
    else if((filter == "expanded") && (!this.nodes[x].collapsed))
      below = below.concat(this.nodes[x].all_below(filter));
  }

  return below;
};

// user clicked, collapse the tree below this node
abctree_node.prototype.collapse = function(item){
  "use strict";
  if(item.table_row.children[0].className != "abctree_leaf"){
    item.table_row.children[0].className = "abctree_collapsed";
    item.collapsed = true;
    var below = item.all_below();
    below.forEach(function(e){e.hide();});
  }
};

// user clicked, expand the tree below this node
abctree_node.prototype.expand = function(item){
  "use strict";
  if(item.table_row.children[0].className != "abctree_leaf"){
    item.table_row.children[0].className = "abctree_expanded";
    item.collapsed = false;
    var below = item.nodes;
    var below = below.concat(item.all_below("expanded"));
    below.forEach(function(e){e.show();});
  }
};

// user clicked, either expand or collapse based on state
abctree_node.prototype.toggle_expanded = function(item){
  "use strict";
  if(item.table_row.children[0].className == "abctree_expanded")
    item.collapse(item);
  else if(item.table_row.children[0].className == "abctree_collapsed")
    item.expand(item);
};

// save the instance info for later clicks
abctree_node.prototype.make_callback = function(call, arg){
  "use strict";
  var ret = function(){return call(arg);};
  return ret;
}

// add a child node beneath this one
abctree_node.prototype.add_child = function(id, val, user_cb, after){
  "use strict";
  var found, list, n;
  var child = new abctree_node(this, id, val, after);
  child.indent = this.indent + 10;
  child.table_row.style.margin = "0px 0px 0px " + child.indent + "px";
  child.table_row.style.display = "none";
  child.parent = this;
  child.root = this.root;
  this.table_row.children[0].className = "abctree_collapsed";
  var sel_cb = this.make_callback(this.toggle_expanded, this);
  this.table_row.children[0].onclick = sel_cb;
  sel_cb = child.make_callback(child.select, child);
  var other_cb;
  if(typeof user_cb == "function")
    other_cb = child.make_callback(user_cb, id);
  else
    other_cb = function(){};
  var cb_fn = function(){sel_cb(); other_cb();};
  child.table_row.children[1].onclick = cb_fn;
//  this.nodes.push(child);

  if((typeof after == undefined) || (after == null))
    this.nodes.push(child);
  else {
    found = 0;
    list = [];
    for(n = 0; n < this.nodes.length; n++){
      list.push(this.nodes[n]);
      if(!found && (this.nodes[n] == after)){
        list.push(child);
        found++;
      }
    }
    if(!found)
      list.push(child);
    this.nodes = list;
  }
  child.select();
  this.expand(this);
  return child;
}

// add a child node beneath this one
abctree_node.prototype.delete = function(){
  "use strict";
  var x, nodes, list = this.all_below();
  for(x = 0; x < this.table.rows.length; x++)
    if(this.table.rows[x].id == this.id){
      this.table.deleteRow(x);
      break;
    }
  for(x = 0; x < this.parent.nodes.length; x++)
    if(this.parent.nodes[x] == this){
      nodes = this.parent.nodes.slice(0, x);
      nodes = nodes.concat(this.parent.nodes.slice(x + 1));
      this.parent.nodes = nodes;
    }
  for(x = 0; x < list.length; x++)
    list[x].delete();
}

// search functions
abctree_node.prototype.get_child_by_id = function(id){
  "use strict";
  var children = this.all_below();
  for(var x = 0; x < children.length; x++)
    if(children[x].id == id)
      return children[x];

  return null;
}

abctree_node.prototype.get_child_by_val = function(val){
  "use strict";
  var children = this.all_below();
  for(var x = 0; x < children.length; x++)
    if(children[x].val == val)
      return children[x];

  return null;
};

// locate insertion point
abctree_node.prototype.last_node_under = function(after){
  var all, ins;

  if(after != null){
    all = [];
    all.push(after);
    all = all.concat(after.all_below());
    ins = all[all.length - 1];
  }
  else if(this.parent.nodes.length == 0)
    ins = this.parent;
  else {
    all = this.parent.all_below();
    ins = all[all.length - 1];
  }

  return ins;
};<|endoftext|>


<commit_before>adminNav.push({
  route: 'searchLogs',
  label: 'Search Logs'
});

Meteor.startup(function () {

  PostsSearchController = PostsListController.extend({
    view: 'search',
    onBeforeAction: function() {
      if ("q" in this.params) {
        Session.set("searchQuery", this.params.q);
      }
      this.next();
    }
  });

  Router.onBeforeAction(Router._filters.isAdmin, {only: ['logs']});

  // Search

  Router.route('/search/:limit?', {
    name: 'search',
    controller: PostsSearchController
  });

  // Search Logs

  Router.route('/logs/:limit?', {
    name: 'searchLogs',
    waitOn: function () {
      var limit = this.params.limit || 100;
      if(Meteor.isClient) {
        Session.set('logsLimit', limit);
      }
      return Meteor.subscribe('searches', limit);
    },
    data: function () {
      return Searches.find({}, {sort: {timestamp: -1}});
    },
    fastRender: true
  });

});
<commit_msg>Fix search query parsing<commit_after>adminNav.push({
  route: 'searchLogs',
  label: 'Search Logs'
});

Meteor.startup(function () {

  PostsSearchController = PostsListController.extend({
    view: 'search',
    onBeforeAction: function() {
      if ("q" in this.params.query) {
        Session.set("searchQuery", this.params.query.q);
      }
      this.next();
    }
  });

  Router.onBeforeAction(Router._filters.isAdmin, {only: ['logs']});

  // Search

  Router.route('/search/:limit?', {
    name: 'search',
    controller: PostsSearchController
  });

  // Search Logs

  Router.route('/logs/:limit?', {
    name: 'searchLogs',
    waitOn: function () {
      var limit = this.params.limit || 100;
      if(Meteor.isClient) {
        Session.set('logsLimit', limit);
      }
      return Meteor.subscribe('searches', limit);
    },
    data: function () {
      return Searches.find({}, {sort: {timestamp: -1}});
    },
    fastRender: true
  });

});
<|endoftext|>


<commit_before>
/**
 * @fileoverview Stylish reporter
 * @author  Matthew Harrison-Jones & ESLint (https://github.com/eslint/eslint/blob/113c81f49712e3d86db1b112c37ce3b900f6c25e/lib/formatters/stylish.js)
 */
'use strict'

var chalk = require('chalk'),
    table = require('text-table')

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

/**
 * Given a word and a count, append an s if count is not one.
 * @param {string} word A word in its singular form.
 * @param {int} count A number controlling whether word should be pluralized.
 * @returns {string} The original word with an s on the end if count is not one.
 */
function pluralize(word, count) {
    return (count === 1 ? word : word + 's')
}

//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------

module.exports = function(results) {

    var output = '\n',
        total = 0,
        errors = 0,
        warnings = 0,
        summaryColor = 'yellow'

    results.forEach(function(result) {
        var messages = result.messages

        if (messages.length === 0) {
            return
        }

        total += messages.length
        output += chalk.underline(result.url + ' — ' + result.summary) + '\n'

        output += table(
            messages.map(function(message) {
                var messageType

                if (message.severity === 2) {
                    messageType = chalk.red('error')
                    summaryColor = 'red'
                    errors++
                } else {
                    messageType = chalk.yellow('warning')
                    warnings++
                }

                return [
                    '',
                    messageType,
                    message.message.replace(/\.$/, ''),
                    chalk.dim(message.ruleId || '')
                ]
            }),
            {
                align: ['', 'r', 'l'],
                stringLength: function(str) {
                    return chalk.stripColor(str).length
                }
            }
        ).split('\n').map(function(el) {
            return el.replace(/(\d+)\s+(\d+)/, function(m, p1, p2) {
                return chalk.dim(p1 + ':' + p2)
            })
        }).join('\n') + '\n\n'
    })

    if (total > 0) {
        output += chalk[summaryColor].bold([
            '\u2716 ', total, pluralize(' problem', total),
            ' (', errors, pluralize(' error', errors), ', ',
            warnings, pluralize(' warning', warnings), ')\n'
        ].join(''))
    }

    return total > 0 ? output : ''
}
<commit_msg>Fix: Remove unnecessary formatting from 'stylish'<commit_after>
/**
 * @fileoverview Stylish reporter
 * @author  Matthew Harrison-Jones & ESLint (https://github.com/eslint/eslint/blob/113c81f49712e3d86db1b112c37ce3b900f6c25e/lib/formatters/stylish.js)
 */
'use strict'

var chalk = require('chalk'),
    table = require('text-table')

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

/**
 * Given a word and a count, append an s if count is not one.
 * @param {string} word A word in its singular form.
 * @param {int} count A number controlling whether word should be pluralized.
 * @returns {string} The original word with an s on the end if count is not one.
 */
function pluralize(word, count) {
    return (count === 1 ? word : word + 's')
}

//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------

module.exports = function(results) {

    var output = '\n',
        total = 0,
        errors = 0,
        warnings = 0,
        summaryColor = 'yellow'

    results.forEach(function(result) {
        var messages = result.messages

        if (messages.length === 0) {
            return
        }

        total += messages.length
        output += chalk.underline(result.url + ' — ' + result.summary) + '\n'

        output += table(
            messages.map(function(message) {
                var messageType

                if (message.severity === 2) {
                    messageType = chalk.red('error')
                    summaryColor = 'red'
                    errors++
                } else {
                    messageType = chalk.yellow('warning')
                    warnings++
                }

                return [
                    '',
                    messageType,
                    message.message.replace(/\.$/, ''),
                    chalk.dim(message.ruleId || '')
                ]
            }),
            {
                align: ['', 'r', 'l'],
                stringLength: function(str) {
                    return chalk.stripColor(str).length
                }
            }
        ) + '\n\n'
    })

    if (total > 0) {
        output += chalk[summaryColor].bold([
            '\u2716 ', total, pluralize(' problem', total),
            ' (', errors, pluralize(' error', errors), ', ',
            warnings, pluralize(' warning', warnings), ')\n'
        ].join(''))
    }

    return total > 0 ? output : ''
}
<|endoftext|>


<commit_before>/*
 * jsCalendar language extension v1.0
 * Add Norwegian Language support
 * Copyright (c) 2017 Grammatopoulos Athanasios-Vasileios
 */

// We love anonymous functions
(function(){

    // Get library
    var jsCalendar = window.jsCalendar;

    // If jsCalendar is not loaded
    if (typeof jsCalendar === "undefined") {
        // If there is no language to load array
        if (typeof window.jsCalendar_language2load === "undefined") {
            window.jsCalendar_language2load = [];
        }
        // Wrapper to add language to load list
        jsCalendar = {
            addLanguage : function (language) {
                // Add language to load list
                window.jsCalendar_language2load.push(language);
            }
        };
    }

    // Add a new language
    jsCalendar.addLanguage({
        // Language code
        // EDIT HERE THE LANGUAGE CODE ~~~~~~~~~~
        code : "no",
        // STOP EDIT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // Months of the year
        months : [
            // EDIT HERE THE MONTHS ~~~~~~~~~~~~~
            "Januar",
            "Februar",
            "Mars",
            "April",
            "Mai",
            "Juni",
            "Juli",
            "August",
            "September",
            "Oktober",
            "November",
            "Desember"
            // STOP EDIT ~~~~~~~~~~~~~~~~~~~~~~~~
        ],
        // Days of the week
        days : [
            // EDIT HERE THE DAYS ~~~~~~~~~~~~~~~
            "Søndag",
            "Mandag",
            "Tirsdag",
            "Onsdag",
            "Torsdag",
            "Fredag",
            "Lørdag"
            // STOP EDIT ~~~~~~~~~~~~~~~~~~~~~~~~
        ]
    });

})();
<commit_msg>Added translator's info (translated by @SpellCraft)<commit_after>/*
 * jsCalendar language extension v1.0
 * Add Norwegian Language support
 * Translator: SpellCraft@github
 */

// We love anonymous functions
(function(){

    // Get library
    var jsCalendar = window.jsCalendar;

    // If jsCalendar is not loaded
    if (typeof jsCalendar === "undefined") {
        // If there is no language to load array
        if (typeof window.jsCalendar_language2load === "undefined") {
            window.jsCalendar_language2load = [];
        }
        // Wrapper to add language to load list
        jsCalendar = {
            addLanguage : function (language) {
                // Add language to load list
                window.jsCalendar_language2load.push(language);
            }
        };
    }

    // Add a new language
    jsCalendar.addLanguage({
        // Language code
        code : "no",
        // Months of the year
        months : [
            "Januar",
            "Februar",
            "Mars",
            "April",
            "Mai",
            "Juni",
            "Juli",
            "August",
            "September",
            "Oktober",
            "November",
            "Desember"
        ],
        // Days of the week
        days : [
            "Søndag",
            "Mandag",
            "Tirsdag",
            "Onsdag",
            "Torsdag",
            "Fredag",
            "Lørdag"
        ]
    });

})();
<|endoftext|>


<commit_before>'use strict';

var util = require('util');
var path = require('path');
var fs = require('fs');
var sqlite3 = require('sqlite3').verbose();
var Bot = require('slackbots');

var NorrisBot = function Constructor(settings) {
    this.settings = settings;
    this.dbPath = settings.dbPath || path.resolve(process.cwd(), 'data', 'norrisbot.db');

    this.userInstance = null;
    this.db = null;
};

util.inherits(NorrisBot, Bot);

NorrisBot.prototype.run = function () {
    NorrisBot.super_.call(this, this.settings);

    this.on('start', this.onStart);
    this.on('message', this.onMessage);
};

NorrisBot.prototype.onStart = function () {
    this.loadBotId();
    this.connectDb();
    this.firstRunCheck();
    this.welcomeMessage();
};

NorrisBot.prototype.onMessage = function (message) {
    if (this.isChatMessage(message) &&
        this.isChannelConversation(message) &&
        !this.isFromNorrisBot(message) &&
        this.isMentioningChuckNorris(message)
    ) {
        this.replyWithRandomJoke(message);
    }
};

NorrisBot.prototype.replyWithRandomJoke = function (originalMessage) {
    var self = this;
    self.db.get('SELECT id, joke FROM jokes ORDER BY used ASC, RANDOM() LIMIT 1', function (err, record) {
        if (err) {
            return console.error('DATABASE ERROR:', err);
        }

        var channel = self.getChannelById(originalMessage.channel);
        self.postMessageToChannel(channel.name, record.joke, {as_user: true});
        self.db.run('UPDATE jokes SET used = used + 1 WHERE id = ?', record.id);
    });
};

NorrisBot.prototype.loadBotId = function () {
    var self = this;
    this.userInstance = this.users.filter(function (user) {
        return user.name === self.name;
    })[0];
};

NorrisBot.prototype.connectDb = function () {
    if (!fs.existsSync(this.dbPath)) {
        console.error('Database path ' + '"' + this.dbPath + '" does not exists or it\'s not readable.');
        process.exit(1);
    }

    this.db = new sqlite3.Database(this.dbPath);
};

NorrisBot.prototype.firstRunCheck = function () {
    // TODO use the table info to see if it's the first time it is run
};

NorrisBot.prototype.welcomeMessage = function () {
    this.postMessageToChannel(this.channels[0].name, 'Hi guys, roundhouse-kick anyone?', {as_user: true});
};

NorrisBot.prototype.isChatMessage = function (message) {
    return message.type === 'message' && message.text;
};

NorrisBot.prototype.isChannelConversation = function (message) {
    return typeof message.channel === 'string' &&
        message.channel[0] === 'C'
        ;
};

NorrisBot.prototype.isMentioningChuckNorris = function (message) {
    return message.text.toLowerCase().indexOf('chuck norris') > -1;
};

NorrisBot.prototype.isFromNorrisBot = function (message) {
    return message.user === this.userInstance.id;
};

NorrisBot.prototype.getChannelById = function (channelId) {
    return this.channels.filter(function (item) {
        return item.id === channelId;
    })[0];
};

module.exports = NorrisBot;
<commit_msg>minor improvements<commit_after>'use strict';

var util = require('util');
var path = require('path');
var fs = require('fs');
var SQLite = require('sqlite3').verbose();
var Bot = require('slackbots');

var NorrisBot = function Constructor(settings) {
    this.settings = settings;
    this.dbPath = settings.dbPath || path.resolve(process.cwd(), 'data', 'norrisbot.db');

    this.userInstance = null;
    this.db = null;
};

util.inherits(NorrisBot, Bot);

NorrisBot.prototype.run = function () {
    NorrisBot.super_.call(this, this.settings);

    this.on('start', this.onStart);
    this.on('message', this.onMessage);
};

NorrisBot.prototype.onStart = function () {
    this.loadBotId();
    this.connectDb();
    this.firstRunCheck();
    this.welcomeMessage();
};

NorrisBot.prototype.onMessage = function (message) {
    if (this.isChatMessage(message) &&
        this.isChannelConversation(message) &&
        !this.isFromNorrisBot(message) &&
        this.isMentioningChuckNorris(message)
    ) {
        this.replyWithRandomJoke(message);
    }
};

NorrisBot.prototype.replyWithRandomJoke = function (originalMessage) {
    var self = this;
    self.db.get('SELECT id, joke FROM jokes ORDER BY used ASC, RANDOM() LIMIT 1', function (err, record) {
        if (err) {
            return console.error('DATABASE ERROR:', err);
        }

        var channel = self.getChannelById(originalMessage.channel);
        self.postMessageToChannel(channel.name, record.joke, {as_user: true});
        self.db.run('UPDATE jokes SET used = used + 1 WHERE id = ?', record.id);
    });
};

NorrisBot.prototype.loadBotId = function () {
    var self = this;
    this.userInstance = this.users.filter(function (user) {
        return user.name === self.name;
    })[0];
};

NorrisBot.prototype.connectDb = function () {
    if (!fs.existsSync(this.dbPath)) {
        console.error('Database path ' + '"' + this.dbPath + '" does not exists or it\'s not readable.');
        process.exit(1);
    }

    this.db = new SQLite.Database(this.dbPath);
};

NorrisBot.prototype.firstRunCheck = function () {
    // TODO use the table info to see if it's the first time it is run
};

NorrisBot.prototype.welcomeMessage = function () {
    this.postMessageToChannel(this.channels[0].name, 'Hi guys, roundhouse-kick anyone?', {as_user: true});
};

NorrisBot.prototype.isChatMessage = function (message) {
    return message.type === 'message' && message.text;
};

NorrisBot.prototype.isChannelConversation = function (message) {
    return typeof message.channel === 'string' &&
        message.channel[0] === 'C'
        ;
};

NorrisBot.prototype.isMentioningChuckNorris = function (message) {
    return message.text.toLowerCase().indexOf('chuck norris') > -1 ||
        message.text.toLowerCase().indexOf(this.name) > -1;
};

NorrisBot.prototype.isFromNorrisBot = function (message) {
    return message.user === this.userInstance.id;
};

NorrisBot.prototype.getChannelById = function (channelId) {
    return this.channels.filter(function (item) {
        return item.id === channelId;
    })[0];
};

module.exports = NorrisBot;
<|endoftext|>


<commit_before>exports = module.exports = function(IoC, logger) {

  return Promise.resolve()
    .then(function() {
      return IoC.create('./registry/hosts');
    });
};

exports['@implements'] = 'http://i.bixbyjs.org/sd/Registry';
exports['@require'] = [
  '!container',
  'http://i.bixbyjs.org/Logger'
];
<commit_msg>Stub in registry discovery.<commit_after>exports = module.exports = function(IoC, logger) {

  return Promise.resolve()
    .then(function discoverService() {
      console.log('discover service...');
      var components = IoC.components('http://i.bixbyjs.org/sd/RegistryDiscoverFunc');

      return Promise.all(components.map(function(c) { return c.create(); } ))
        .then(function(funcs) {
          return new Promise(function(resolve, reject) {

            // Iterate over each of the `discover` functions, attempting to
            // locate a service registry.
            (function iter(i) {
              var func = funcs[i];
              if (!func) {
                // Reject with `ENOTFOUND`, causing a jump to the next catch
                // function.  This function will attempt to create a suitable
                // store based on the host environment.
                //return reject('ENOTFOUND');
                return resolve();
              }

              logger.debug('Discovering service registry via ' + components[i].a['@service']);
              func(function(err, records) {
                if (err && err.code == 'ENOTFOUND') {
                  // Unable to locate a service using this particular protocol.
                  // Continue discovery using remaining supported protocols.
                  return iter(i + 1);
                } else if (err) {
                  return reject(err);
                }

                if (!records) { return iter(i + 1); }
                return resolve(records);
              });
            })(0);

          });
        });
    })
    .then(function(records) {
      console.log('CREATE HOSTS REGISTRY!');
      console.log(records)

      return IoC.create('./registry/hosts');
    });
};

exports['@implements'] = 'http://i.bixbyjs.org/sd/Registry';
exports['@require'] = [
  '!container',
  'http://i.bixbyjs.org/Logger'
];
<|endoftext|>


<commit_before>/*leaflet -- control*/
// import './leaflet/control/ChangeTileVersionSpec.js';

/*leaflet -- core*/
import './leaflet/core/NonEarthCRSSpec.js';
import './leaflet/core/TransformUtilSpec.js';
import './leaflet/core/Proj4LeafletSpec.js';

/*leaflet -- mapping*/
import './leaflet/mapping/ImageMapLayerSpec.js';
import './leaflet/mapping/TiledMapLayerSpec.js';
import './leaflet/mapping/TileLayer.WMTSSpec.js';
// import './leaflet/mapping/WebMapSpec.js';

/*leaflet -- overlay*/

import './leaflet/overlay/EchartsLayerSpec.js';
/*deck相关测试未通过，待解决后打开注释*/
import './leaflet/overlay/graphic/GraphicSpec.js';
import './leaflet/overlay/GraphicLayerSpec.js';
import './leaflet/overlay/graphic/CloverStyleSpec';
import './leaflet/overlay/GraphThemeLayerSpec.js';
import './leaflet/overlay/HeatMapLayerSpec.js';
import './leaflet/overlay/LabelThemeLayerSpec.js';
import './leaflet/overlay/MapVLayerSpec.js';
import './leaflet/overlay/RangeThemeLayerSpec.js';
import './leaflet/overlay/RankSymbolThemeLayerSpec.js';
import './leaflet/overlay/TileVectorLayerSpec.js';
import './leaflet/overlay/UniqueThemeLayerSpec.js';
import './leaflet/overlay/vectortile/PointSymbolizerSpec.js';
import './leaflet/overlay/vectortile/TextSymbolizerSpec.js';
import './leaflet/overlay/TurfLayerSpec.js';
import './leaflet/overlay/mapv/MapVRendererSpec.js';
/**leaflet -- services**/
import './leaflet/services/AddressMatchServiceSpec.js';
import './leaflet/services/BufferAnalysisSpec.js';
import './leaflet/services/DensityAnalysisSpec.js';
import './leaflet/services/EditFeaturesLineSpec.js';
import './leaflet/services/EditFeaturesPointSpec.js';
import './leaflet/services/EditFeaturesRegionSpec.js';
import './leaflet/services/FieldServiceSpec.js';
import './leaflet/services/GenerateSpatialDataSpec.js';
import './leaflet/services/GeoRelationAnalysisSpec.js';
import './leaflet/services/GeometryBatchAnalysisSpec.js';
import './leaflet/services/GetFeaturesByBoundsSpec.js';
import './leaflet/services/GetFeaturesByBufferSpec.js';
import './leaflet/services/GetFeaturesByGeometrySpec.js';
import './leaflet/services/GetFeaturesByIDsSpec.js';
import './leaflet/services/GetFeaturesBySQLSpec.js';
import './leaflet/services/GridCellInfosServiceSpec.js';
import './leaflet/services/InterpolationAnalysisSpec.js';
import './leaflet/services/LayerInfoServiceSpec.js';
import './leaflet/services/MapServiceSpec.js';
import './leaflet/services/MathExpressionAnalysisSpec.js';
import './leaflet/services/MeasureServiceSpec.js';
import './leaflet/services/NetworkAnalystServiceSpec.js';
import './leaflet/services/OverlayAnalysisSpec.js';
import './leaflet/services/ProcessingServiceSpec.js';
import './leaflet/services/QueryByBoundsSpec.js';
import './leaflet/services/QueryByDistanceSpec.js';
import './leaflet/services/QueryByGeometrySpec.js';
import './leaflet/services/QueryBySQLSpec.js';
import './leaflet/services/RouteCalculateMeasureSpec.js';
import './leaflet/services/RouteLocateSpec.js';
import './leaflet/services/SurfaceAnalysisSpec.js';
import './leaflet/services/TerrainCurvatureCalculateSpec.js';
import './leaflet/services/ThemeServiceSpec.js';
import './leaflet/services/ThiessenAnalysisSpec.js';
import './leaflet/services/TrafficTransferAnalystServiceSpec.js';

/* component */
import './leaflet/components/openfile/OpenFileViewSpec.js';
// import './leaflet/components/dataservicequery/DataServiceQueryViewSpec.js';
import './leaflet/components/distributedanalysis/DistributedAnalysisViewSpec.js';
import './leaflet/components/clientcomputation/ClientComputationViewSpec.js';
import './leaflet/components/search/SearchViewSpec.js';
import './leaflet/components/dataflow/DataFlowViewSpec.js';
import './leaflet/overlay/DataFlowLayerSpec.js';

<commit_msg>Update test-main-leaflet.js<commit_after>/*leaflet -- control*/
import './leaflet/control/ChangeTileVersionSpec.js';

/*leaflet -- core*/
import './leaflet/core/NonEarthCRSSpec.js';
import './leaflet/core/TransformUtilSpec.js';
import './leaflet/core/Proj4LeafletSpec.js';

/*leaflet -- mapping*/
import './leaflet/mapping/ImageMapLayerSpec.js';
import './leaflet/mapping/TiledMapLayerSpec.js';
import './leaflet/mapping/TileLayer.WMTSSpec.js';
// import './leaflet/mapping/WebMapSpec.js';

/*leaflet -- overlay*/

import './leaflet/overlay/EchartsLayerSpec.js';
/*deck相关测试未通过，待解决后打开注释*/
import './leaflet/overlay/graphic/GraphicSpec.js';
import './leaflet/overlay/GraphicLayerSpec.js';
import './leaflet/overlay/graphic/CloverStyleSpec';
import './leaflet/overlay/GraphThemeLayerSpec.js';
import './leaflet/overlay/HeatMapLayerSpec.js';
import './leaflet/overlay/LabelThemeLayerSpec.js';
import './leaflet/overlay/MapVLayerSpec.js';
import './leaflet/overlay/RangeThemeLayerSpec.js';
import './leaflet/overlay/RankSymbolThemeLayerSpec.js';
import './leaflet/overlay/TileVectorLayerSpec.js';
import './leaflet/overlay/UniqueThemeLayerSpec.js';
import './leaflet/overlay/vectortile/PointSymbolizerSpec.js';
import './leaflet/overlay/vectortile/TextSymbolizerSpec.js';
import './leaflet/overlay/TurfLayerSpec.js';
import './leaflet/overlay/mapv/MapVRendererSpec.js';
/**leaflet -- services**/
import './leaflet/services/AddressMatchServiceSpec.js';
import './leaflet/services/BufferAnalysisSpec.js';
import './leaflet/services/DensityAnalysisSpec.js';
import './leaflet/services/EditFeaturesLineSpec.js';
import './leaflet/services/EditFeaturesPointSpec.js';
import './leaflet/services/EditFeaturesRegionSpec.js';
import './leaflet/services/FieldServiceSpec.js';
import './leaflet/services/GenerateSpatialDataSpec.js';
import './leaflet/services/GeoRelationAnalysisSpec.js';
import './leaflet/services/GeometryBatchAnalysisSpec.js';
import './leaflet/services/GetFeaturesByBoundsSpec.js';
import './leaflet/services/GetFeaturesByBufferSpec.js';
import './leaflet/services/GetFeaturesByGeometrySpec.js';
import './leaflet/services/GetFeaturesByIDsSpec.js';
import './leaflet/services/GetFeaturesBySQLSpec.js';
import './leaflet/services/GridCellInfosServiceSpec.js';
import './leaflet/services/InterpolationAnalysisSpec.js';
import './leaflet/services/LayerInfoServiceSpec.js';
import './leaflet/services/MapServiceSpec.js';
import './leaflet/services/MathExpressionAnalysisSpec.js';
import './leaflet/services/MeasureServiceSpec.js';
import './leaflet/services/NetworkAnalystServiceSpec.js';
import './leaflet/services/OverlayAnalysisSpec.js';
import './leaflet/services/ProcessingServiceSpec.js';
import './leaflet/services/QueryByBoundsSpec.js';
import './leaflet/services/QueryByDistanceSpec.js';
import './leaflet/services/QueryByGeometrySpec.js';
import './leaflet/services/QueryBySQLSpec.js';
import './leaflet/services/RouteCalculateMeasureSpec.js';
import './leaflet/services/RouteLocateSpec.js';
import './leaflet/services/SurfaceAnalysisSpec.js';
import './leaflet/services/TerrainCurvatureCalculateSpec.js';
import './leaflet/services/ThemeServiceSpec.js';
import './leaflet/services/ThiessenAnalysisSpec.js';
import './leaflet/services/TrafficTransferAnalystServiceSpec.js';

/* component */
import './leaflet/components/openfile/OpenFileViewSpec.js';
import './leaflet/components/dataservicequery/DataServiceQueryViewSpec.js';
import './leaflet/components/distributedanalysis/DistributedAnalysisViewSpec.js';
import './leaflet/components/clientcomputation/ClientComputationViewSpec.js';
import './leaflet/components/search/SearchViewSpec.js';
import './leaflet/components/dataflow/DataFlowViewSpec.js';
import './leaflet/overlay/DataFlowLayerSpec.js';

<|endoftext|>


<commit_before>if (typeof (require) != 'undefined') {
	var loader = require('../../node_modules/Butterfly-js/dist/butterfly.min.js').loader;
}

/**
 * Entry point of the game, contains some part of the game engine and deals with
 * the different entities
 */
loader.executeModule('main',
'B', 'Canvas', 'Entities', 'Physics', 'Utils', 'data', 'Controls', 'Level', 'GUI',
function (B, canvas, Entities, Physics, Utils, data, Controls, Level, GUI) {
	var level,
		walls = [],
		nbPlayers = 2,
		players = [],
		playerControls = [
			{gasKey: KEY_UP_ARROW, reverseKey: KEY_DOWN_ARROW, leftKey: KEY_LEFT_ARROW, rightKey: KEY_RIGHT_ARROW},
			{gasKey: KEY_W, reverseKey: KEY_S, leftKey: KEY_A, rightKey: KEY_D}
		];
		fps = 30,
		urlParams = Utils.getUrlParams(window.location.search);

	const DEBUG = urlParams.debug || NO_DEBUG;

	B.on(window, 'load', function () {
		// Init the view
		canvas.init(document.getElementById('game-canvas'));
		Controls.init(true);

		loadResources(function () {
			setInterval(updateAll, 1000 / fps);

			level = Level.createLevel(data, 0);

			// Init the car

			for (var p = 0; p < data.maps[0].start.length && p < nbPlayers; p++) {
				var startCell = level.getCoordinatesCenterCell(data.maps[0].start[p][0], data.maps[0].start[p][1]),
					car = new Entities.Car('MyCar', startCell[0], startCell[1], Math.PI / 2, CAR_SPEED);
				car.setGraphic(data.resources[data.resourcesMap.CAR].resource);
				players.push(car);
			}
		});

		function key (code, pressed, car, controls) {
			if (code == controls.leftKey) {
				car.steerLeft(pressed);
			}
			else if (code == controls.gasKey) {
				car.accelerate(pressed);
			}
			else if (code == controls.rightKey) {
				car.steerRight(pressed);
			}
			else if (code == controls.reverseKey) {
				car.reverse(pressed);
			}
		}

		B.Events.on('keydown', null, function (code) {
			for (var p = 0; p < nbPlayers; p++) {
				key(code, true, players[p], playerControls[p]);
			}
		});

		B.Events.on('keyup', null, function (code) {
			for (var p = 0; p < nbPlayers; p++) {
				key(code, false, players[p], playerControls[p]);
			}
		});
	});

	/* Events */
	// Event to execute when the player wins
	B.Events.on('win', null, function (winner) {
		console.log('And the winner is: ' + winner.name);
		for (var p = 0; p < nbPlayers; p++) {
			players[p].reset();
		}
	});
	/* End of Events */

	function loadResources (loadedCallback) {
		var r, loaded = 0,
			loadingPadding = canvas.width() / 5,
			loadingWidth = 3 * loadingPadding;

		if (!data.resources) {
			loadedCallback();
			return;
		}

		canvas.clearScreen();
		GUI.progressBar(
			loadingPadding, canvas.height() / 2,
			loadingWidth, 30,
			0,
			'black', 'white', 'black'
		);
		for (r = 0; r < data.resources.length; r++) {
			data.resources[r].resource = new Image();
			data.resources[r].resource.onload = function () {
				if (++loaded == data.resources.length) {
					loadedCallback();
				}
				else {
					GUI.progressBar(
						loadingPadding, canvas.height() / 2,
						loadingWidth, 30,
						loaded / data.resources.length,
						'black', 'white', 'black'
					);
				}
			};
			data.resources[r].resource.src = data.resources[r].url;
		}
	}

	/**
	 * Method to update the game state and the objects's position
	 */
	function moveAll () {
		for (var p = 0; p < nbPlayers; p++) {
			// Update the cars position
			players[p].updatePosition();

			var carGridCellCol = Math.floor(players[p].x / level.gridCellWidth),
				carGridCellRow = Math.floor(players[p].y / level.gridCellHeight);

			/* Car and wall collision */
			var tileUnderCar = level.getCell(
				carGridCellCol,
				carGridCellRow
			);

			// if the car is on a wall
			if (0 <= carGridCellCol && carGridCellCol < level.width
				&& 0 <= carGridCellRow && carGridCellRow < level.height
			) {
				if (data.resources[tileUnderCar.state].obstacle) {
					players[p].bumpBack();
				}
				else if (tileUnderCar.state == data.resourcesMap.TILE_FINISH) {
					B.Events.fire('win', [players[p]]);
				}
			}
			else {
				players[p].bumpBack();
			}
			/* End of Car and wall collision */
		}
	}

	/**
	 * Method to execute on each frame to update the game state and the
	 * objects's position and then redraw the canvas
	 */
	function updateAll () {
		moveAll();
		canvas.drawAll([level.cells, players]);
	}
});
<commit_msg>engine used with app<commit_after>if (typeof (require) != 'undefined') {
	var loader = require('../../node_modules/Butterfly-js/dist/butterfly.min.js').loader;
}

/**
 * Entry point of the game, contains some part of the game engine and deals with
 * the different entities
 */
loader.executeModule('main',
'B', 'Engine', 'Canvas', 'Entities', 'Physics', 'Utils', 'data', 'Controls', 'Level', 'GUI',
function (B, Engine, canvas, Entities, Physics, Utils, data, Controls, Level, GUI) {
	var level,
		walls = [],
		nbPlayers = 2,
		players = [],
		playerControls = [
			{gasKey: KEY_UP_ARROW, reverseKey: KEY_DOWN_ARROW, leftKey: KEY_LEFT_ARROW, rightKey: KEY_RIGHT_ARROW},
			{gasKey: KEY_W, reverseKey: KEY_S, leftKey: KEY_A, rightKey: KEY_D}
		];
		fps = 30,
		urlParams = Utils.getUrlParams(window.location.search);

	const DEBUG = urlParams.debug || NO_DEBUG;

	Engine.init(
		document.getElementById('game-canvas'),
		Engine.OPTION_USE_KEYBOARD,
		function () {
			// Init the car
			for (var p = 0; p < data.maps[0].start.length && p < nbPlayers; p++) {
				var startCell = Engine.getLevel().getCoordinatesCenterCell(data.maps[0].start[p][0], data.maps[0].start[p][1]),
					car = new Entities.Car('MyCar', startCell[0], startCell[1], Math.PI / 2, CAR_SPEED);
				car.setGraphic(data.resources[data.resourcesMap.CAR].resource);
				players.push(car);
			}

			Engine.addDrawable(players);
		}
	);

	function key (code, pressed, car, controls) {
		if (code == controls.leftKey) {
			car.steerLeft(pressed);
		}
		else if (code == controls.gasKey) {
			car.accelerate(pressed);
		}
		else if (code == controls.rightKey) {
			car.steerRight(pressed);
		}
		else if (code == controls.reverseKey) {
			car.reverse(pressed);
		}
	}

	B.Events.on('keydown', null, function (code) {
		for (var p = 0; p < nbPlayers; p++) {
			key(code, true, players[p], playerControls[p]);
		}
	});

	B.Events.on('keyup', null, function (code) {
		for (var p = 0; p < nbPlayers; p++) {
			key(code, false, players[p], playerControls[p]);
		}
	});

	Engine.addCallback('win', function (winner) {
		console.log('And the winner is: ' + winner.name);
		for (var p = 0; p < nbPlayers; p++) {
			players[p].reset();
		}
	});

	/**
	 * Method to update the game state and the objects's position
	 */
	Engine.addCallback('moveAll', function () {
		for (var p = 0; p < nbPlayers; p++) {
			// Update the cars position
			players[p].updatePosition();

			var carGridCellCol = Math.floor(players[p].x / Engine.getLevel().gridCellWidth),
				carGridCellRow = Math.floor(players[p].y / Engine.getLevel().gridCellHeight);

			/* Car and wall collision */
			var tileUnderCar = Engine.getLevel().getCell(
				carGridCellCol,
				carGridCellRow
			);

			// if the car is on a wall
			if (0 <= carGridCellCol && carGridCellCol < Engine.getLevel().width
				&& 0 <= carGridCellRow && carGridCellRow < Engine.getLevel().height
			) {
				if (data.resources[tileUnderCar.state].obstacle) {
					players[p].bumpBack();
				}
				else if (tileUnderCar.state == data.resourcesMap.TILE_FINISH) {
					B.Events.fire('win', [players[p]]);
				}
			}
			else {
				players[p].bumpBack();
			}
			/* End of Car and wall collision */
		}
	});
});
<|endoftext|>


<commit_before>import '../icons/check-circle-o-large'
import '../icons/info-circle-o-large'
import '../icons/cross-circle-o-large'
import config from 'veui/managers/config'

config.defaults({
  icons: {
    success: 'check-circle-o-large',
    info: 'info-circle-o-large',
    error: 'cross-circle-o-large'
  },
  ui: {
    type: {
      values: ['success', 'error', 'info']
    }
  }
}, 'alertbox')
<commit_msg>refactor: remove unnecessary ui prop def<commit_after>import '../icons/check-circle-o-large'
import '../icons/info-circle-o-large'
import '../icons/cross-circle-o-large'
import config from 'veui/managers/config'

config.defaults({
  icons: {
    success: 'check-circle-o-large',
    info: 'info-circle-o-large',
    error: 'cross-circle-o-large'
  }
}, 'alertbox')
<|endoftext|>