<commit_before>/**
 * The command line interface for interacting with the Protractor runner.
 * It takes care of parsing command line options.
 *
 * Values from command line options override values from the config.
 */
'use strict';

var args = [];

process.argv.slice(2).forEach(function(arg) {
  var flag = arg.split('=')[0];

  switch (flag) {
    case 'debug':
      args.push('--nodeDebug');
      args.push('true');
      break;
    case '-d':
    case '--debug':
    case '--debug-brk':
      args.push('--v8Debug');
      args.push('true');
      break;
    default:
      args.push(arg);
      break;
  }
});

var path = require('path');
var fs = require('fs');
var optimist = require('optimist').
    usage('Usage: protractor [options] [configFile]\n' +
        'configFile defaults to protractor.conf.js\n' +
        'The [options] object will override values from the config file.\n' +
        'See the reference config for a full list of options.').
    describe('help', 'Print Protractor help menu').
    describe('version', 'Print Protractor version').
    describe('browser', 'Browsername, e.g. chrome or firefox').
    describe('seleniumAddress', 'A running selenium address to use').
    describe('seleniumServerJar', 'Location of the standalone selenium jar file').
    describe('seleniumPort', 'Optional port for the selenium standalone server').
    describe('baseUrl', 'URL to prepend to all relative paths').
    describe('rootElement', 'Element housing ng-app, if not html or body').
    describe('specs', 'Comma-separated list of files to test').
    describe('exclude', 'Comma-separated list of files to exclude').
    describe('verbose', 'Print full spec names').
    describe('stackTrace', 'Print stack trace on error').
    describe('params', 'Param object to be passed to the tests').
    describe('framework', 'Test framework to use: jasmine, cucumber or mocha').
    describe('resultJsonOutputFile', 'Path to save JSON test result').
    describe('troubleshoot', 'Turn on troubleshooting output').
    describe('elementExplorer', 'Interactively test Protractor commands').
    describe('debuggerServerPort', 'Start a debugger server at specified port instead of repl').
    alias('browser', 'capabilities.browserName').
    alias('name', 'capabilities.name').
    alias('platform', 'capabilities.platform').
    alias('platform-version', 'capabilities.version').
    alias('tags', 'capabilities.tags').
    alias('build', 'capabilities.build').
    alias('verbose', 'jasmineNodeOpts.isVerbose').
    alias('stackTrace', 'jasmineNodeOpts.includeStackTrace').
    alias('grep', 'jasmineNodeOpts.grep').
    alias('invert-grep', 'jasmineNodeOpts.invertGrep').
    alias('explorer', 'elementExplorer').
    string('capabilities.tunnel-identifier').
    check(function(arg) {
      if (arg._.length > 1) {
        throw 'Error: more than one config file specified';
      }
    });

var argv = optimist.parse(args);

if (argv.help) {
  optimist.showHelp();
  process.exit(0);
}

if (argv.version) {
  console.log('Version ' + require(path.join(__dirname, '../package.json')).version);
  process.exit(0);
}

// WebDriver capabilities properties require dot notation, but optimist parses
// that into an object. Re-flatten it.
var flattenObject = function(obj) {
  var prefix = arguments[1] || '';
  var out = arguments[2] || {};
    for (var prop in obj) {
      if (obj.hasOwnProperty(prop)) {
        typeof obj[prop] === 'object' ?
            flattenObject(obj[prop], prefix + prop + '.', out) :
            out[prefix + prop] = obj[prop];
      }
    }
  return out;
};

if (argv.capabilities) {
  argv.capabilities = flattenObject(argv.capabilities);
}

/**
 * Helper to resolve comma separated lists of file pattern strings relative to
 * the cwd.
 *
 * @private
 * @param {Array} list
 */
var processFilePatterns_ = function(list) {
  var patterns = list.split(',');
  patterns.forEach(function(spec, index, arr) {
    arr[index] = path.resolve(process.cwd(), spec);
  });
  return patterns;
};

if (argv.specs) {
  argv.specs = processFilePatterns_(argv.specs);
}
if (argv.exclude) {
  argv.exclude = processFilePatterns_(argv.exclude);
}

// Use default configuration, if it exists.
var configFile = argv._[0];
if (!configFile) {
  if (fs.existsSync('./protractor.conf.js')) {
    configFile = './protractor.conf.js';
  }
}

if (!configFile && !argv.elementExplorer && args.length < 3) {
  console.log('**you must either specify a configuration file ' +
    'or at least 3 options. See below for the options:\n');
  optimist.showHelp();
  process.exit(1);
}

// Run the launcher
require('./launcher').init(configFile, argv);
<commit_msg>chore(cli): make usage message clearer<commit_after>/**
 * The command line interface for interacting with the Protractor runner.
 * It takes care of parsing command line options.
 *
 * Values from command line options override values from the config.
 */
'use strict';

var args = [];

process.argv.slice(2).forEach(function(arg) {
  var flag = arg.split('=')[0];

  switch (flag) {
    case 'debug':
      args.push('--nodeDebug');
      args.push('true');
      break;
    case '-d':
    case '--debug':
    case '--debug-brk':
      args.push('--v8Debug');
      args.push('true');
      break;
    default:
      args.push(arg);
      break;
  }
});

var path = require('path');
var fs = require('fs');
var optimist = require('optimist').
    usage('Usage: protractor [configFile] [options]\n' +
        'configFile defaults to protractor.conf.js\n' +
        'The [options] object will override values from the config file.\n' +
        'See the reference config for a full list of options.').
    describe('help', 'Print Protractor help menu').
    describe('version', 'Print Protractor version').
    describe('browser', 'Browsername, e.g. chrome or firefox').
    describe('seleniumAddress', 'A running selenium address to use').
    describe('seleniumServerJar', 'Location of the standalone selenium jar file').
    describe('seleniumPort', 'Optional port for the selenium standalone server').
    describe('baseUrl', 'URL to prepend to all relative paths').
    describe('rootElement', 'Element housing ng-app, if not html or body').
    describe('specs', 'Comma-separated list of files to test').
    describe('exclude', 'Comma-separated list of files to exclude').
    describe('verbose', 'Print full spec names').
    describe('stackTrace', 'Print stack trace on error').
    describe('params', 'Param object to be passed to the tests').
    describe('framework', 'Test framework to use: jasmine, cucumber or mocha').
    describe('resultJsonOutputFile', 'Path to save JSON test result').
    describe('troubleshoot', 'Turn on troubleshooting output').
    describe('elementExplorer', 'Interactively test Protractor commands').
    describe('debuggerServerPort', 'Start a debugger server at specified port instead of repl').
    alias('browser', 'capabilities.browserName').
    alias('name', 'capabilities.name').
    alias('platform', 'capabilities.platform').
    alias('platform-version', 'capabilities.version').
    alias('tags', 'capabilities.tags').
    alias('build', 'capabilities.build').
    alias('verbose', 'jasmineNodeOpts.isVerbose').
    alias('stackTrace', 'jasmineNodeOpts.includeStackTrace').
    alias('grep', 'jasmineNodeOpts.grep').
    alias('invert-grep', 'jasmineNodeOpts.invertGrep').
    alias('explorer', 'elementExplorer').
    string('capabilities.tunnel-identifier').
    check(function(arg) {
      if (arg._.length > 1) {
        throw 'Error: more than one config file specified';
      }
    });

var argv = optimist.parse(args);

if (argv.help) {
  optimist.showHelp();
  process.exit(0);
}

if (argv.version) {
  console.log('Version ' + require(path.join(__dirname, '../package.json')).version);
  process.exit(0);
}

// WebDriver capabilities properties require dot notation, but optimist parses
// that into an object. Re-flatten it.
var flattenObject = function(obj) {
  var prefix = arguments[1] || '';
  var out = arguments[2] || {};
    for (var prop in obj) {
      if (obj.hasOwnProperty(prop)) {
        typeof obj[prop] === 'object' ?
            flattenObject(obj[prop], prefix + prop + '.', out) :
            out[prefix + prop] = obj[prop];
      }
    }
  return out;
};

if (argv.capabilities) {
  argv.capabilities = flattenObject(argv.capabilities);
}

/**
 * Helper to resolve comma separated lists of file pattern strings relative to
 * the cwd.
 *
 * @private
 * @param {Array} list
 */
var processFilePatterns_ = function(list) {
  var patterns = list.split(',');
  patterns.forEach(function(spec, index, arr) {
    arr[index] = path.resolve(process.cwd(), spec);
  });
  return patterns;
};

if (argv.specs) {
  argv.specs = processFilePatterns_(argv.specs);
}
if (argv.exclude) {
  argv.exclude = processFilePatterns_(argv.exclude);
}

// Use default configuration, if it exists.
var configFile = argv._[0];
if (!configFile) {
  if (fs.existsSync('./protractor.conf.js')) {
    configFile = './protractor.conf.js';
  }
}

if (!configFile && !argv.elementExplorer && args.length < 3) {
  console.log('**you must either specify a configuration file ' +
    'or at least 3 options. See below for the options:\n');
  optimist.showHelp();
  process.exit(1);
}

// Run the launcher
require('./launcher').init(configFile, argv);
<|endoftext|>


<commit_before>'use strict';

var program = require('commander'),
    _ = require('lodash'),
    fs = require('fs'),
    async = require('async'),
    scan = require('./scan');

function run(program, source) {
    var paths = source.split(',').map(function(path) {
        return path + '/**/*';
    });

    async.map(paths, scan, function(err, results) {
        var strings = results.reduce(function(strings, result) {
            return strings.concat(result);
        }, []);

        strings = _.uniq(strings).sort().reduce(function(strings, string) {
            strings[string] = string;
            return strings;
        }, {});

        if (program.output) return fs.writeFile(program.output, JSON.stringify(strings, null, 2), process.exit);

        console.log(JSON.stringify(strings, null, 2));

        return process.exit();
    });
}

program
    .command('*')
    .description('Scans for gettext functions __("literal") and __n("single", "plural", n )')
    .action(function(source) {
        run(program, source);
    });

program
    .version('0.0.1')
    .option('-o, --output [file]', 'Output file', String)
    .parse(process.argv);

if (program.args.length === 0) program.help();
<commit_msg>prevent rewriting (#2)<commit_after>'use strict';

var program = require('commander'),
    _ = require('lodash'),
    fs = require('fs'),
    async = require('async'),
    scan = require('./scan');

function run(program, source) {
    var paths = source.split(',').map(function(path) {
        return path + '/**/*';
    });

    async.map(paths, scan, function(err, results) {
        var strings = results.reduce(function(strings, result) {
            return strings.concat(result);
        }, []);

        var existing = {};
        try {
          existing = JSON.parse(fs.readFileSync(program.output));
        } catch(err) {
          // nothing
        }

        strings = _.uniq(strings).sort().reduce(function(strings, string) {
            if(string in existing) {
              strings[string] = existing[string];
            } else {
              strings[string] = string;
            }
            return strings;
        }, {});

        if (program.output) return fs.writeFile(program.output, JSON.stringify(strings, null, 2), process.exit);

        console.log(JSON.stringify(strings, null, 2));

        return process.exit();
    });
}

program
    .command('*')
    .description('Scans for gettext functions __("literal") and __n("single", "plural", n )')
    .action(function(source) {
        run(program, source);
    });

program
    .version('0.0.1')
    .option('-o, --output [file]', 'Output file', String)
    .parse(process.argv);

if (program.args.length === 0) program.help();
<|endoftext|>


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

var pkg = require('../package.json');
var yosay = require('./yosay');
var argv = require('minimist')(process.argv.slice(2));

function stdin(cb) {
  var ret = '';
  process.stdin.setEncoding('utf8');
  process.stdin.on('data', function (data) { ret += data });
  process.stdin.on('end', function () { cb(ret) }).resume();
}

function help() {
  console.log(pkg.description);
  console.log('');
  console.log('Usage');
  console.log('  $ echo <string> | yosay');
  console.log('  $ echo <string> | yosay --maxLength 8');
  console.log('');
  console.log('Example');
  console.log('  $ echo "Sindre is a horse" | yosay');
  console.log(yosay('Sindre is a horse'));
}

function logMessage(message) {
  console.log(yosay(message, argv));
}

if (argv.h || argv.help) {
  help();
  return;
}

if (argv.v || argv.version) {
  console.log(pkg.version);
  return;
}

if (process.stdin.isTTY) {
  help();
  return;
} else {
  stdin(logMessage);
}
<commit_msg>jshint tweaks.<commit_after>#!/usr/bin/env node
'use strict';

var pkg = require('../package.json');
var yosay = require('./yosay');
var argv = require('minimist')(process.argv.slice(2));

function stdin(cb) {
  var ret = '';
  process.stdin.setEncoding('utf8');
  process.stdin.on('data', function (data) { ret += data; });
  process.stdin.on('end', function () { cb(ret); }).resume();
}

function help() {
  console.log(pkg.description);
  console.log('');
  console.log('Usage');
  console.log('  $ echo <string> | yosay');
  console.log('  $ echo <string> | yosay --maxLength 8');
  console.log('');
  console.log('Example');
  console.log('  $ echo "Sindre is a horse" | yosay');
  console.log(yosay('Sindre is a horse'));
}

function logMessage(message) {
  console.log(yosay(message, argv));
}

if (argv.h || argv.help) {
  help();
  return;
}

if (argv.v || argv.version) {
  console.log(pkg.version);
  return;
}

if (process.stdin.isTTY) {
  help();
  return;
} else {
  stdin(logMessage);
}
<|endoftext|>


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

const fs = require('fs')
const path = require('path')
const os = require('os')

const Bronze = require('../')
const packageInfo = require('../package')

const defaultSequencePath = path._makeLong(path.join(os.homedir(), '.bronze', 'sequence'))

function displayHelp () {
  const helpText = `
  bronze ${packageInfo.version}

  ${packageInfo.description}

  Usage: bronze [options]

  Options:
    --sequence INT          Set the counter for the number of ids generated
                            By default will use sequence file (sequence path)
                            If set sequence file will not be updated
    --pid INT               Set the process id for generated ids
    --name STRING           A unique name for the generator
                            Any slashes will be replaced with underscores
    --spec STRING           Set the spec

    --gen, -g INT           The number of ids to create. Must be >= 0.
                            Default = 1
    --list-specs            Get the specs available from this version of bronze
    --sequence-dir STRING   Set the sequence directory
                            Will attempt to create if not exist
    --sequence-reset        Sets the sequence back to 0
                            File isn't created if it doesn't exist

    --help, -h
    --version, -v

  Notes:
    - Same name + same time + different machines = bad idea (collisions)
    - If any option is invalid will fallback to default
    - Any unknown arguments will cause help to print
    - Subsequent options of the same type will override existing:
      - Ex: \`bronze -g 1 -g 3\` will generate 3 ids
    - Options can be set in 2 styles if they require a value:
      - arg, arg    Ex: \`--sequence 1\`
      - equals      Ex: \`--sequence=1\`
    - Option Resolution:
      - If Help needs to print or requested, print. Process ends.
      - If List Specs requested, print. Process ends.
      - If version requested, print. Process ends.
      - Reset Sequence File, if requested.
      - If sequence option, use. Else read/create sequence directory
      - Generate requested ids with given options

  Default Sequence Path:
    - ${defaultSequencePath}

  README.md:
    - ${path.join(__dirname, '..', 'README.md')}

  Bugs:
    - Email: ${packageInfo.bugs.email}
    - URL: ${packageInfo.bugs.url}

  License: ${packageInfo.license}`

  console.log(helpText)
}

function displaySpecs () {
  console.log(Object.keys(Bronze.specs).join(' '))
}
function displayVersion () {
  console.log(packageInfo.version)
}

function updateSequenceFile (sequencePath, sequenceCount) {
  fs.writeFileSync(sequencePath, `${sequenceCount}`, 'utf8')
}

function readFromSequenceFile (sequencePath) {
  function makeIfDirDoesntExist (givenPath) {
    const baseDir = path.parse(givenPath).dir

    try {
      fs.mkdirSync(baseDir)
    } catch (e) {
      if (e.code === 'EEXIST') {
        return baseDir
      } else if (e.code === 'ENOENT' && baseDir !== givenPath) {
        makeIfDirDoesntExist(baseDir)
      } else {
        throw e
      }
    }
  }

  try {
    const sequenceCountCandidate = Number(fs.readFileSync(sequencePath, 'utf8'))

    if (Number.isSafeInteger(sequenceCountCandidate) === true) {
      return sequenceCountCandidate
    }
  } catch (e) {
    if (e.code === 'ENOENT') {
      makeIfDirDoesntExist(sequencePath)
    } else {
      throw e
    }

    return 0
  }
}

function generateIds (options, count, sequencePath) {
  const idGen = new Bronze(options)

  for (let i = 0; i < count; i++) {
    console.log(idGen.generate())
  }

  if (typeof sequencePath === 'string') {
    updateSequenceFile(sequencePath, idGen.sequence)
  }
}

function parseCommand () {
  const givenArgs = process.argv.slice(2)
  let bronzeOptions = {}
  let generateIdCount = 1
  let sequencePath = defaultSequencePath
  let isHelp = false
  let isListSpecs = false
  let isVersion = false
  let resetSequenceFile = false

  for (let i = 0, len = givenArgs.length; i < len; i++) {
    const arg = givenArgs[i].trim()
    let advanceAdditional = false
    let advanceAdditionalCandidate = false
    let valueCandidate = null

    if (arg.indexOf('--pid') === 0) {
      if (arg.indexOf('--pid=') === 0) {
        valueCandidate = Number(arg.slice('--pid='.length))
      } else {
        valueCandidate = Number(givenArgs[i + 1])
        advanceAdditionalCandidate = true
      }

      if (Number.isSafeInteger(valueCandidate) === true) {
        bronzeOptions.pid = valueCandidate
        if (advanceAdditionalCandidate === true) {
          advanceAdditional = true
        }
      }
    } else if (arg.indexOf('--name') === 0) {
      if (arg.indexOf('--name=') === 0) {
        valueCandidate = arg.slice('--name='.length)
      } else {
        valueCandidate = givenArgs[i + 1]
        advanceAdditionalCandidate = true
      }

      if (typeof valueCandidate === 'string') {
        bronzeOptions.name = valueCandidate
        if (advanceAdditionalCandidate === true) {
          advanceAdditional = true
        }
      }
    } else if (arg.indexOf('--spec') === 0) {
      if (arg.indexOf('--spec=') === 0) {
        valueCandidate = arg.slice('--spec='.length)
      } else {
        valueCandidate = givenArgs[i + 1]
        advanceAdditionalCandidate = true
      }

      if (typeof valueCandidate === 'string') {
        bronzeOptions.spec = valueCandidate
        if (advanceAdditionalCandidate === true) {
          advanceAdditional = true
        }
      }
    } else if (arg.indexOf('--gen') === 0) {
      if (arg.indexOf('--gen=') === 0) {
        valueCandidate = Number(arg.slice('--gen='.length))
      } else {
        valueCandidate = Number(givenArgs[i + 1])
        advanceAdditionalCandidate = true
      }

      if (Number.isSafeInteger(valueCandidate) === true && valueCandidate >= 0) {
        generateIdCount = valueCandidate
        if (advanceAdditionalCandidate === true) {
          advanceAdditional = true
        }
      }
    } else if (arg.indexOf('-g') === 0) {
      if (arg.indexOf('-g=') === 0) {
        valueCandidate = Number(arg.slice('-g='.length))
      } else {
        valueCandidate = Number(givenArgs[i + 1])
        advanceAdditionalCandidate = true
      }

      if (Number.isSafeInteger(valueCandidate) === true && valueCandidate >= 0) {
        generateIdCount = valueCandidate
        if (advanceAdditionalCandidate === true) {
          advanceAdditional = true
        }
      }
    } else if (arg.indexOf('--list-specs') === 0) {
      isListSpecs = true
    } else if (arg.indexOf('--sequence-dir') === 0) {
      if (arg.indexOf('--sequence-dir=') === 0) {
        valueCandidate = arg.slice('--sequence-dir='.length)
      } else {
        valueCandidate = givenArgs[i + 1]
        advanceAdditionalCandidate = true
      }

      if (typeof valueCandidate === 'string') {
        sequencePath = path._makeLong(path.join(valueCandidate, 'sequence'))
        if (advanceAdditionalCandidate === true) {
          advanceAdditional = true
        }
      }
    } else if (arg.indexOf('--sequence-reset') === 0) {
      resetSequenceFile = true
    } else if (arg.indexOf('--sequence') === 0) {
      if (arg.indexOf('--sequence=') === 0) {
        valueCandidate = Number(arg.slice('--sequence='.length))
      } else {
        valueCandidate = Number(givenArgs[i + 1])
        advanceAdditionalCandidate = true
      }

      if (Number.isSafeInteger(valueCandidate) === true) {
        bronzeOptions.sequence = valueCandidate
        if (advanceAdditionalCandidate === true) {
          advanceAdditional = true
        }
      }
    } else if (arg.indexOf('--help') === 0 || arg.indexOf('-h') === 0) {
      isHelp = true
    } else if (arg.indexOf('--version') === 0 || arg.indexOf('-v') === 0) {
      isVersion = true
    } else {
      isHelp = true
    }

    if (advanceAdditional === true) {
      i++
    }
  }

  if (isHelp === true) {
    displayHelp()
  } else if (isListSpecs === true) {
    displaySpecs()
  } else if (isVersion === true) {
    displayVersion()
  } else {
    if (resetSequenceFile === true) {
      try {
        updateSequenceFile(sequencePath, 0)
      } catch (e) {
        if (e.code !== 'ENOENT') {
          throw e
        }
      }
    }

    if (typeof bronzeOptions.sequence === 'number') {
      generateIds(bronzeOptions, generateIdCount)
    } else {
      bronzeOptions.sequence = readFromSequenceFile(sequencePath)
      generateIds(bronzeOptions, generateIdCount, sequencePath)
    }
  }
}

parseCommand()
<commit_msg>Bonus: available specs in --help output<commit_after>#! /usr/bin/env node
'use strict'

const fs = require('fs')
const path = require('path')
const os = require('os')

const Bronze = require('../')
const packageInfo = require('../package')

const defaultSequencePath = path._makeLong(path.join(os.homedir(), '.bronze', 'sequence'))

function displayHelp () {
  const helpText = `
  bronze ${packageInfo.version}

  ${packageInfo.description}

  Usage: bronze [options]

  Options:
    --sequence INT          Set the counter for the number of ids generated
                            By default will use sequence file (sequence path)
                            If set sequence file will not be updated
    --pid INT               Set the process id for generated ids
    --name STRING           A unique name for the generator
                            Any slashes will be replaced with underscores
    --spec STRING           Set the spec

    --gen, -g INT           The number of ids to create. Must be >= 0.
                            Default = 1
    --list-specs            Get the specs available from this version of bronze
    --sequence-dir STRING   Set the sequence directory
                            Will attempt to create if not exist
    --sequence-reset        Sets the sequence back to 0
                            File isn't created if it doesn't exist

    --help, -h
    --version, -v

  Notes:
    - Same name + same time + different machines = bad idea (collisions)
    - If any option is invalid will fallback to default
    - Any unknown arguments will cause help to print
    - Subsequent options of the same type will override existing:
      - Ex: \`bronze -g 1 -g 3\` will generate 3 ids
    - Options can be set in 2 styles if they require a value:
      - arg, arg    Ex: \`--sequence 1\`
      - equals      Ex: \`--sequence=1\`
    - Option Resolution:
      - If Help needs to print or requested, print. Process ends.
      - If List Specs requested, print. Process ends.
      - If version requested, print. Process ends.
      - Reset Sequence File, if requested.
      - If sequence option, use. Else read/create sequence directory
      - Generate requested ids with given options

  Available Specs:
    - ${Object.keys(Bronze.specs).join(' ')}

  Default Sequence Path:
    - ${defaultSequencePath}

  README.md:
    - ${path.join(__dirname, '..', 'README.md')}

  Bugs:
    - Email: ${packageInfo.bugs.email}
    - URL: ${packageInfo.bugs.url}

  License: ${packageInfo.license}`

  console.log(helpText)
}

function displaySpecs () {
  console.log(Object.keys(Bronze.specs).join(' '))
}
function displayVersion () {
  console.log(packageInfo.version)
}

function updateSequenceFile (sequencePath, sequenceCount) {
  fs.writeFileSync(sequencePath, `${sequenceCount}`, 'utf8')
}

function readFromSequenceFile (sequencePath) {
  function makeIfDirDoesntExist (givenPath) {
    const baseDir = path.parse(givenPath).dir

    try {
      fs.mkdirSync(baseDir)
    } catch (e) {
      if (e.code === 'EEXIST') {
        return baseDir
      } else if (e.code === 'ENOENT' && baseDir !== givenPath) {
        makeIfDirDoesntExist(baseDir)
      } else {
        throw e
      }
    }
  }

  try {
    const sequenceCountCandidate = Number(fs.readFileSync(sequencePath, 'utf8'))

    if (Number.isSafeInteger(sequenceCountCandidate) === true) {
      return sequenceCountCandidate
    }
  } catch (e) {
    if (e.code === 'ENOENT') {
      makeIfDirDoesntExist(sequencePath)
    } else {
      throw e
    }

    return 0
  }
}

function generateIds (options, count, sequencePath) {
  const idGen = new Bronze(options)

  for (let i = 0; i < count; i++) {
    console.log(idGen.generate())
  }

  if (typeof sequencePath === 'string') {
    updateSequenceFile(sequencePath, idGen.sequence)
  }
}

function parseCommand () {
  const givenArgs = process.argv.slice(2)
  let bronzeOptions = {}
  let generateIdCount = 1
  let sequencePath = defaultSequencePath
  let isHelp = false
  let isListSpecs = false
  let isVersion = false
  let resetSequenceFile = false

  for (let i = 0, len = givenArgs.length; i < len; i++) {
    const arg = givenArgs[i].trim()
    let advanceAdditional = false
    let advanceAdditionalCandidate = false
    let valueCandidate = null

    if (arg.indexOf('--pid') === 0) {
      if (arg.indexOf('--pid=') === 0) {
        valueCandidate = Number(arg.slice('--pid='.length))
      } else {
        valueCandidate = Number(givenArgs[i + 1])
        advanceAdditionalCandidate = true
      }

      if (Number.isSafeInteger(valueCandidate) === true) {
        bronzeOptions.pid = valueCandidate
        if (advanceAdditionalCandidate === true) {
          advanceAdditional = true
        }
      }
    } else if (arg.indexOf('--name') === 0) {
      if (arg.indexOf('--name=') === 0) {
        valueCandidate = arg.slice('--name='.length)
      } else {
        valueCandidate = givenArgs[i + 1]
        advanceAdditionalCandidate = true
      }

      if (typeof valueCandidate === 'string') {
        bronzeOptions.name = valueCandidate
        if (advanceAdditionalCandidate === true) {
          advanceAdditional = true
        }
      }
    } else if (arg.indexOf('--spec') === 0) {
      if (arg.indexOf('--spec=') === 0) {
        valueCandidate = arg.slice('--spec='.length)
      } else {
        valueCandidate = givenArgs[i + 1]
        advanceAdditionalCandidate = true
      }

      if (typeof valueCandidate === 'string') {
        bronzeOptions.spec = valueCandidate
        if (advanceAdditionalCandidate === true) {
          advanceAdditional = true
        }
      }
    } else if (arg.indexOf('--gen') === 0) {
      if (arg.indexOf('--gen=') === 0) {
        valueCandidate = Number(arg.slice('--gen='.length))
      } else {
        valueCandidate = Number(givenArgs[i + 1])
        advanceAdditionalCandidate = true
      }

      if (Number.isSafeInteger(valueCandidate) === true && valueCandidate >= 0) {
        generateIdCount = valueCandidate
        if (advanceAdditionalCandidate === true) {
          advanceAdditional = true
        }
      }
    } else if (arg.indexOf('-g') === 0) {
      if (arg.indexOf('-g=') === 0) {
        valueCandidate = Number(arg.slice('-g='.length))
      } else {
        valueCandidate = Number(givenArgs[i + 1])
        advanceAdditionalCandidate = true
      }

      if (Number.isSafeInteger(valueCandidate) === true && valueCandidate >= 0) {
        generateIdCount = valueCandidate
        if (advanceAdditionalCandidate === true) {
          advanceAdditional = true
        }
      }
    } else if (arg.indexOf('--list-specs') === 0) {
      isListSpecs = true
    } else if (arg.indexOf('--sequence-dir') === 0) {
      if (arg.indexOf('--sequence-dir=') === 0) {
        valueCandidate = arg.slice('--sequence-dir='.length)
      } else {
        valueCandidate = givenArgs[i + 1]
        advanceAdditionalCandidate = true
      }

      if (typeof valueCandidate === 'string') {
        sequencePath = path._makeLong(path.join(valueCandidate, 'sequence'))
        if (advanceAdditionalCandidate === true) {
          advanceAdditional = true
        }
      }
    } else if (arg.indexOf('--sequence-reset') === 0) {
      resetSequenceFile = true
    } else if (arg.indexOf('--sequence') === 0) {
      if (arg.indexOf('--sequence=') === 0) {
        valueCandidate = Number(arg.slice('--sequence='.length))
      } else {
        valueCandidate = Number(givenArgs[i + 1])
        advanceAdditionalCandidate = true
      }

      if (Number.isSafeInteger(valueCandidate) === true) {
        bronzeOptions.sequence = valueCandidate
        if (advanceAdditionalCandidate === true) {
          advanceAdditional = true
        }
      }
    } else if (arg.indexOf('--help') === 0 || arg.indexOf('-h') === 0) {
      isHelp = true
    } else if (arg.indexOf('--version') === 0 || arg.indexOf('-v') === 0) {
      isVersion = true
    } else {
      isHelp = true
    }

    if (advanceAdditional === true) {
      i++
    }
  }

  if (isHelp === true) {
    displayHelp()
  } else if (isListSpecs === true) {
    displaySpecs()
  } else if (isVersion === true) {
    displayVersion()
  } else {
    if (resetSequenceFile === true) {
      try {
        updateSequenceFile(sequencePath, 0)
      } catch (e) {
        if (e.code !== 'ENOENT') {
          throw e
        }
      }
    }

    if (typeof bronzeOptions.sequence === 'number') {
      generateIds(bronzeOptions, generateIdCount)
    } else {
      bronzeOptions.sequence = readFromSequenceFile(sequencePath)
      generateIds(bronzeOptions, generateIdCount, sequencePath)
    }
  }
}

parseCommand()
<|endoftext|>


<commit_before>const Promise = require('bluebird');
const Moment = require('moment');

const server = require('./../../server.js');
const CollectionService = require('./../Collection/Service.js');

const Models = server.sequelize.models;
const SLocation = Models.Location;

const Service = {
  getLocationsList: () => {
    const processedLocations = [];
    return SLocation.findAll().then(rawLocations => new Promise((resolve) => {
      rawLocations.forEach((location) => {
        processedLocations.push({
          id: location.id,
          name: location.name,
          latitude: location.latitude,
          longitude: location.longitude,
          radius: location.radius,
        });
      });
      resolve(processedLocations);
    }));
  },
  createLocation: (location) => {
    const DEFAULT_LOCATION = {
      name: 'DEFAULT',
      latitude: 33.9698,
      longitude: -118.4169,
      radius: 0.003,
    };

    const data = DEFAULT_LOCATION;
    data.name = location.name || data.name;
    data.latitude = location.latitude || data.latitude;
    data.longitude = location.longitude || data.longitude;
    data.radius = location.radius || data.radius;

    return SLocation.create(data).then(rawLocation => new Promise((resolve) => {
      resolve({
        id: rawLocation.id,
        name: rawLocation.name,
        latitude: rawLocation.latitude,
        longitude: rawLocation.longitude,
        radius: rawLocation.radius,
      });
    }));
  },
  getLocation: id => SLocation.findById(id).then(rawLocation => new Promise((resolve, reject) => {
    if (!rawLocation) reject({ code: 404 });
    resolve({
      id: rawLocation.id,
      name: rawLocation.name,
      latitude: rawLocation.latitude,
      longitude: rawLocation.longitude,
      radius: rawLocation.radius,
    });
  })),
  getLocationCount: (id, query) => SLocation.findById(id)
  .then((location) => {
    if (!location) return Promise.reject({ code: 404 });
    const timeSlices = [];
    if (query.start && query.end && query.slice) {
      let previousTime = Moment(query.end);
      for (let time = Moment(query.end).subtract(query.slice, 'minutes');
      time.isSameOrAfter(Moment(query.start));
      time = time.subtract(query.slice, 'minutes')) {
        timeSlices.push({
          start: time.toISOString(),
          end: previousTime.toISOString(),
        });
        previousTime = Moment(time);
      }
    } else {
      timeSlices.push({
        start: Moment().subtract(1, 'hours'),
        end: Moment(),
      });
    }
    return Promise.map(timeSlices, (slice) => {
      console.log(slice);
      return CollectionService.getAddressesWithinRange({
        latitude: location.latitude,
        longitude: location.longitude,
        radius: location.radius,
        start: slice.start,
        end: slice.end,
      });
    });
  })
  .catch((error) => {
    console.log(error);
    return Promise.reject(error);
  }),
};

module.exports = Service;
<commit_msg>Correct the order of counts<commit_after>const Promise = require('bluebird');
const Moment = require('moment');

const server = require('./../../server.js');
const CollectionService = require('./../Collection/Service.js');

const Models = server.sequelize.models;
const SLocation = Models.Location;

const Service = {
  getLocationsList: () => {
    const processedLocations = [];
    return SLocation.findAll().then(rawLocations => new Promise((resolve) => {
      rawLocations.forEach((location) => {
        processedLocations.push({
          id: location.id,
          name: location.name,
          latitude: location.latitude,
          longitude: location.longitude,
          radius: location.radius,
        });
      });
      resolve(processedLocations);
    }));
  },
  createLocation: (location) => {
    const DEFAULT_LOCATION = {
      name: 'DEFAULT',
      latitude: 33.9698,
      longitude: -118.4169,
      radius: 0.003,
    };

    const data = DEFAULT_LOCATION;
    data.name = location.name || data.name;
    data.latitude = location.latitude || data.latitude;
    data.longitude = location.longitude || data.longitude;
    data.radius = location.radius || data.radius;

    return SLocation.create(data).then(rawLocation => new Promise((resolve) => {
      resolve({
        id: rawLocation.id,
        name: rawLocation.name,
        latitude: rawLocation.latitude,
        longitude: rawLocation.longitude,
        radius: rawLocation.radius,
      });
    }));
  },
  getLocation: id => SLocation.findById(id).then(rawLocation => new Promise((resolve, reject) => {
    if (!rawLocation) reject({ code: 404 });
    resolve({
      id: rawLocation.id,
      name: rawLocation.name,
      latitude: rawLocation.latitude,
      longitude: rawLocation.longitude,
      radius: rawLocation.radius,
    });
  })),
  getLocationCount: (id, query) => SLocation.findById(id)
  .then((location) => {
    if (!location) return Promise.reject({ code: 404 });
    const timeSlices = [];
    if (query.start && query.end && query.slice) {
      let previousTime = Moment(query.end);
      for (let time = Moment(query.end).subtract(query.slice, 'minutes');
      time.isSameOrAfter(Moment(query.start));
      time = time.subtract(query.slice, 'minutes')) {
        timeSlices.unshift({
          start: time.toISOString(),
          end: previousTime.toISOString(),
        });
        previousTime = Moment(time);
      }
    } else {
      timeSlices.push({
        start: Moment().subtract(1, 'hours'),
        end: Moment(),
      });
    }
    return Promise.map(timeSlices, (slice) => {
      console.log(slice);
      return CollectionService.getAddressesWithinRange({
        latitude: location.latitude,
        longitude: location.longitude,
        radius: location.radius,
        start: slice.start,
        end: slice.end,
      });
    });
  })
  .catch((error) => {
    console.log(error);
    return Promise.reject(error);
  }),
};

module.exports = Service;
<|endoftext|>


<commit_before>/*global _, Dygraph, window, document */

(function () {
  "use strict";
  window.dygraphConfig = {
    defaultFrame : 20 * 60 * 1000,

    zeropad: function (x) {
      if (x < 10) {
        return "0" + x;
      }
      return x;
    },

    xAxisFormat: function (d) {
      if (d === -1) {
        return "";
      }
      var date = new Date(d);
      return this.zeropad(date.getHours()) + ":"
        + this.zeropad(date.getMinutes()) + ":"
        + this.zeropad(date.getSeconds());
    },

    mergeObjects: function (o1, o2, mergeAttribList) {
      if (!mergeAttribList) {
        mergeAttribList = [];
      }
      var vals = {}, res;
      mergeAttribList.forEach(function (a) {
        var valO1 = o1[a],
        valO2 = o2[a];
        if (valO1 === undefined) {
          valO1 = {};
        }
        if (valO2 === undefined) {
          valO2 = {};
        }
        vals[a] = _.extend(valO1, valO2);
      });
      res = _.extend(o1, o2);
      Object.keys(vals).forEach(function (k) {
        res[k] = vals[k];
      });
      return res;
    },

    mapStatToFigure : {
      residentSize : ["times", "residentSizePercent"],
      pageFaults : ["times", "majorPageFaultsPerSecond", "minorPageFaultsPerSecond"],
      systemUserTime : ["times", "systemTimePerSecond", "userTimePerSecond"],
      totalTime : ["times", "avgQueueTime", "avgRequestTime", "avgIoTime"],
      dataTransfer : ["times", "bytesSentPerSecond", "bytesReceivedPerSecond"],
      requests : ["times", "getsPerSecond", "putsPerSecond", "postsPerSecond",
                  "deletesPerSecond", "patchesPerSecond", "headsPerSecond",
                  "optionsPerSecond", "othersPerSecond"]
    },

    //colors for dygraphs
    colors: ["rgb(95, 194, 135)", "rgb(238, 190, 77)", "#81ccd8", "#7ca530", "#3c3c3c",
             "#aa90bd", "#e1811d", "#c7d4b2", "#d0b2d4"],

    // figure dependend options
    figureDependedOptions: {
      clusterRequestsPerSecond: {
        showLabelsOnHighlight: true,
        title: '',
        header : "Cluster Requests per Second",
        stackedGraph: true,
        div: "lineGraphLegend",
        labelsKMG2: false,
        axes: {
          y: {
            valueFormatter: function (y) {
              return parseFloat(y.toPrecision(3));
            },
            axisLabelFormatter: function (y) {
              if (y === 0) {
                return 0;
              }

              return parseFloat(y.toPrecision(3));
            }
          }
        }
      },

      residentSize: {
        header: "Memory",
        axes: {
          y: {
            labelsKMG2: false,
            axisLabelFormatter: function (y) {
              return parseFloat(y.toPrecision(3) * 100) + "%";
            },
            valueFormatter: function (y) {
              return parseFloat(y.toPrecision(3) * 100) + "%";
            }
          }
        }
      },

      pageFaults: {
        header : "Page Faults",
        visibility: [true, false],
        labels: ["datetime", "Major Page", "Minor Page"],
        div: "pageFaultsChart",
        labelsKMG2: false,
        axes: {
          y: {
            valueFormatter: function (y) {
              return parseFloat(y.toPrecision(3));
            },
            axisLabelFormatter: function (y) {
              if (y === 0) {
                return 0;
              }
              return parseFloat(y.toPrecision(3));
            }
          }
        }
      },

      systemUserTime: {
        div: "systemUserTimeChart",
        header: "System and User Time",
        labels: ["datetime", "System Time", "User Time"],
        stackedGraph: true,
        labelsKMG2: false,
        axes: {
          y: {
            valueFormatter: function (y) {
              return parseFloat(y.toPrecision(3));
            },
            axisLabelFormatter: function (y) {
              if (y === 0) {
                return 0;
              }
              return parseFloat(y.toPrecision(3));
            }
          }
        }
      },

      totalTime: {
        div: "totalTimeChart",
        header: "Total Time",
        labels: ["datetime", "Queue", "Computation", "I/O"],
        labelsKMG2: false,
        axes: {
          y: {
            valueFormatter: function (y) {
              return parseFloat(y.toPrecision(3));
            },
            axisLabelFormatter: function (y) {
              if (y === 0) {
                return 0;
              }
              return parseFloat(y.toPrecision(3));
            }
          }
        },
        stackedGraph: true
      },

      dataTransfer: {
        header: "Data Transfer",
        labels: ["datetime", "Bytes sent", "Bytes received"],
        stackedGraph: true,
        div: "dataTransferChart"
      },

      requests: {
        header: "Requests",
        labels: ["datetime", "Reads", "Writes"],
        stackedGraph: true,
        div: "requestsChart",
        axes: {
          y: {
            valueFormatter: function (y) {
              return parseFloat(y.toPrecision(3));
            },
            axisLabelFormatter: function (y) {
              if (y === 0) {
                return 0;
              }
              return parseFloat(y.toPrecision(3));
            }
          }
        }
      }
    },

    getDashBoardFigures : function (all) {
      var result = [], self = this;
      Object.keys(this.figureDependedOptions).forEach(function (k) {
        // ClusterRequestsPerSecond should not be ignored. Quick Fix
        if (k !== "clusterRequestsPerSecond" && (self.figureDependedOptions[k].div || all)) {
          result.push(k);
        }
      });
      return result;
    },

    //configuration for chart overview
    getDefaultConfig: function (figure) {
      var self = this;
      var result = {
        digitsAfterDecimal: 1,
        drawGapPoints: true,
        fillGraph: true,
        fillAlpha: 0.85,
        showLabelsOnHighlight: false,
        strokeWidth: 0.0,
        lineWidth: 0.0,
        strokeBorderWidth: 0.0,
        includeZero: true,
        highlightCircleSize: 2.5,
        labelsSeparateLines : true,
        strokeBorderColor: 'rgba(0,0,0,0)',
        interactionModel: {},
        maxNumberWidth : 10,
        colors: [this.colors[0]],
        xAxisLabelWidth: "50",
        rightGap: 15,
        showRangeSelector: false,
        rangeSelectorHeight: 50,
        rangeSelectorPlotStrokeColor: '#365300',
        rangeSelectorPlotFillColor: '',
        // rangeSelectorPlotFillColor: '#414a4c',
        pixelsPerLabel: 50,
        labelsKMG2: true,
        dateWindow: [
          new Date().getTime() -
            this.defaultFrame,
          new Date().getTime()
        ],
        axes: {
          x: {
            valueFormatter: function (d) {
              return self.xAxisFormat(d);
            }
          },
          y: {
            ticker: Dygraph.numericLinearTicks
          }
        }
      };
      if (this.figureDependedOptions[figure]) {
        result = this.mergeObjects(
          result, this.figureDependedOptions[figure], ["axes"]
        );
        if (result.div && result.labels) {
          result.colors = this.getColors(result.labels);
          result.labelsDiv = document.getElementById(result.div + "Legend");
          result.legend = "always";
          result.showLabelsOnHighlight = true;
        }
      }
      return result;

    },

    getDetailChartConfig: function (figure) {
      var result = _.extend(
        this.getDefaultConfig(figure),
        {
          showRangeSelector: true,
          interactionModel: null,
          showLabelsOnHighlight: true,
          highlightCircleSize: 2.5,
          legend: "always",
          labelsDiv: "div#detailLegend.dashboard-legend-inner"
        }
      );
      if (figure === "pageFaults") {
        result.visibility = [true, true];
      }
      if (!result.labels) {
        result.labels = ["datetime", result.header];
        result.colors = this.getColors(result.labels);
      }
      return result;
    },

    getColors: function (labels) {
      var colorList;
      colorList = this.colors.concat([]);
      return colorList.slice(0, labels.length - 1);
    }
  };
}());
<commit_msg>remove residentSize from dygraph configs since it is not used any more<commit_after>/*global _, Dygraph, window, document */

(function () {
  "use strict";
  window.dygraphConfig = {
    defaultFrame : 20 * 60 * 1000,

    zeropad: function (x) {
      if (x < 10) {
        return "0" + x;
      }
      return x;
    },

    xAxisFormat: function (d) {
      if (d === -1) {
        return "";
      }
      var date = new Date(d);
      return this.zeropad(date.getHours()) + ":"
        + this.zeropad(date.getMinutes()) + ":"
        + this.zeropad(date.getSeconds());
    },

    mergeObjects: function (o1, o2, mergeAttribList) {
      if (!mergeAttribList) {
        mergeAttribList = [];
      }
      var vals = {}, res;
      mergeAttribList.forEach(function (a) {
        var valO1 = o1[a],
        valO2 = o2[a];
        if (valO1 === undefined) {
          valO1 = {};
        }
        if (valO2 === undefined) {
          valO2 = {};
        }
        vals[a] = _.extend(valO1, valO2);
      });
      res = _.extend(o1, o2);
      Object.keys(vals).forEach(function (k) {
        res[k] = vals[k];
      });
      return res;
    },

    mapStatToFigure : {
      pageFaults : ["times", "majorPageFaultsPerSecond", "minorPageFaultsPerSecond"],
      systemUserTime : ["times", "systemTimePerSecond", "userTimePerSecond"],
      totalTime : ["times", "avgQueueTime", "avgRequestTime", "avgIoTime"],
      dataTransfer : ["times", "bytesSentPerSecond", "bytesReceivedPerSecond"],
      requests : ["times", "getsPerSecond", "putsPerSecond", "postsPerSecond",
                  "deletesPerSecond", "patchesPerSecond", "headsPerSecond",
                  "optionsPerSecond", "othersPerSecond"]
    },

    //colors for dygraphs
    colors: ["rgb(95, 194, 135)", "rgb(238, 190, 77)", "#81ccd8", "#7ca530", "#3c3c3c",
             "#aa90bd", "#e1811d", "#c7d4b2", "#d0b2d4"],

    // figure dependend options
    figureDependedOptions: {
      clusterRequestsPerSecond: {
        showLabelsOnHighlight: true,
        title: '',
        header : "Cluster Requests per Second",
        stackedGraph: true,
        div: "lineGraphLegend",
        labelsKMG2: false,
        axes: {
          y: {
            valueFormatter: function (y) {
              return parseFloat(y.toPrecision(3));
            },
            axisLabelFormatter: function (y) {
              if (y === 0) {
                return 0;
              }

              return parseFloat(y.toPrecision(3));
            }
          }
        }
      },

      pageFaults: {
        header : "Page Faults",
        visibility: [true, false],
        labels: ["datetime", "Major Page", "Minor Page"],
        div: "pageFaultsChart",
        labelsKMG2: false,
        axes: {
          y: {
            valueFormatter: function (y) {
              return parseFloat(y.toPrecision(3));
            },
            axisLabelFormatter: function (y) {
              if (y === 0) {
                return 0;
              }
              return parseFloat(y.toPrecision(3));
            }
          }
        }
      },

      systemUserTime: {
        div: "systemUserTimeChart",
        header: "System and User Time",
        labels: ["datetime", "System Time", "User Time"],
        stackedGraph: true,
        labelsKMG2: false,
        axes: {
          y: {
            valueFormatter: function (y) {
              return parseFloat(y.toPrecision(3));
            },
            axisLabelFormatter: function (y) {
              if (y === 0) {
                return 0;
              }
              return parseFloat(y.toPrecision(3));
            }
          }
        }
      },

      totalTime: {
        div: "totalTimeChart",
        header: "Total Time",
        labels: ["datetime", "Queue", "Computation", "I/O"],
        labelsKMG2: false,
        axes: {
          y: {
            valueFormatter: function (y) {
              return parseFloat(y.toPrecision(3));
            },
            axisLabelFormatter: function (y) {
              if (y === 0) {
                return 0;
              }
              return parseFloat(y.toPrecision(3));
            }
          }
        },
        stackedGraph: true
      },

      dataTransfer: {
        header: "Data Transfer",
        labels: ["datetime", "Bytes sent", "Bytes received"],
        stackedGraph: true,
        div: "dataTransferChart"
      },

      requests: {
        header: "Requests",
        labels: ["datetime", "Reads", "Writes"],
        stackedGraph: true,
        div: "requestsChart",
        axes: {
          y: {
            valueFormatter: function (y) {
              return parseFloat(y.toPrecision(3));
            },
            axisLabelFormatter: function (y) {
              if (y === 0) {
                return 0;
              }
              return parseFloat(y.toPrecision(3));
            }
          }
        }
      }
    },

    getDashBoardFigures : function (all) {
      var result = [], self = this;
      Object.keys(this.figureDependedOptions).forEach(function (k) {
        // ClusterRequestsPerSecond should not be ignored. Quick Fix
        if (k !== "clusterRequestsPerSecond" && (self.figureDependedOptions[k].div || all)) {
          result.push(k);
        }
      });
      return result;
    },

    //configuration for chart overview
    getDefaultConfig: function (figure) {
      var self = this;
      var result = {
        digitsAfterDecimal: 1,
        drawGapPoints: true,
        fillGraph: true,
        fillAlpha: 0.85,
        showLabelsOnHighlight: false,
        strokeWidth: 0.0,
        lineWidth: 0.0,
        strokeBorderWidth: 0.0,
        includeZero: true,
        highlightCircleSize: 2.5,
        labelsSeparateLines : true,
        strokeBorderColor: 'rgba(0,0,0,0)',
        interactionModel: {},
        maxNumberWidth : 10,
        colors: [this.colors[0]],
        xAxisLabelWidth: "50",
        rightGap: 15,
        showRangeSelector: false,
        rangeSelectorHeight: 50,
        rangeSelectorPlotStrokeColor: '#365300',
        rangeSelectorPlotFillColor: '',
        // rangeSelectorPlotFillColor: '#414a4c',
        pixelsPerLabel: 50,
        labelsKMG2: true,
        dateWindow: [
          new Date().getTime() -
            this.defaultFrame,
          new Date().getTime()
        ],
        axes: {
          x: {
            valueFormatter: function (d) {
              return self.xAxisFormat(d);
            }
          },
          y: {
            ticker: Dygraph.numericLinearTicks
          }
        }
      };
      if (this.figureDependedOptions[figure]) {
        result = this.mergeObjects(
          result, this.figureDependedOptions[figure], ["axes"]
        );
        if (result.div && result.labels) {
          result.colors = this.getColors(result.labels);
          result.labelsDiv = document.getElementById(result.div + "Legend");
          result.legend = "always";
          result.showLabelsOnHighlight = true;
        }
      }
      return result;

    },

    getDetailChartConfig: function (figure) {
      var result = _.extend(
        this.getDefaultConfig(figure),
        {
          showRangeSelector: true,
          interactionModel: null,
          showLabelsOnHighlight: true,
          highlightCircleSize: 2.5,
          legend: "always",
          labelsDiv: "div#detailLegend.dashboard-legend-inner"
        }
      );
      if (figure === "pageFaults") {
        result.visibility = [true, true];
      }
      if (!result.labels) {
        result.labels = ["datetime", result.header];
        result.colors = this.getColors(result.labels);
      }
      return result;
    },

    getColors: function (labels) {
      var colorList;
      colorList = this.colors.concat([]);
      return colorList.slice(0, labels.length - 1);
    }
  };
}());
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 TopCoder Inc., All Rights Reserved.
 */
"use strict";

/**
 * Represents controller for mock data.
 * @version 1.0
 * @author Sky_
 */

var _ = require("underscore");

// solution entities
var solutions = {
    1: require("../data/solutions/1.json"),
    2: require("../data/solutions/2.json"),
    3: require("../data/solutions/3.json")
};

// project entities
var projects = {
    1: require("../data/projects/1.json"),
    2: require("../data/projects/2.json"),
    3: require("../data/projects/3.json")
};

// service entities
var services = {
    1: require("../data/services/1.json"),
    2: require("../data/services/2.json"),
    3: require("../data/services/3.json"),
    4: require("../data/services/4.json"),
    5: require("../data/services/5.json"),
    6: require("../data/services/6.json"),
    7: require("../data/services/7.json"),
    8: require("../data/services/8.json"),
    9: require("../data/services/9.json"),
    10: require("../data/services/10.json"),
    11: require("../data/services/11.json"),
    12: require("../data/services/12.json"),
    13: require("../data/services/13.json"),
    14: require("../data/services/14.json"),
    15: require("../data/services/15.json")
};

// application entities
var applications = {
    1: require("../data/applications/1.json"),
    2: require("../data/applications/2.json"),
    3: require("../data/applications/3.json"),
    4: require("../data/applications/4.json")
};

// bundle entities
var bundles = {
    1: require("../data/bundles/1.json"),
    2: require("../data/bundles/2.json"),
    3: require("../data/bundles/3.json")
};

// all data displayed in header
var header = require("../data/header.json");

// dropdown values for new project
var projectQuestions = require("../data/project_questions.json");

// dropdown values for manage view
var manageValues = require("../data/manage.json");

// values for marketplace
var marketplaceValues = require("../data/marketplace.json");

// alerts for dashboard and manage
var alerts = require("../data/alerts.json");

// alerts with x icon for dashboard
var alertPopup = require("../data/alert-popup.json");

var staffSignIn = require("../data/staff/sign_in.json");

var currentUser = require("../data/current_user.json");

/**
 * Populate references.
 * @param {Object} target the elements to populate (hashmap id to element)
 * @param {String} fieldName the name of the field to be populated
 * @param {Object} source the referenced elements (hashmap id to element)
 * @private
 */
function _populate(target, fieldName, source) {
    _.each(target, function (item) {
        item[fieldName] = _.map(item[fieldName], function (id) {
            return source[id];
        });
    });
}

_populate(solutions, "projects", projects);
_populate(solutions, "services", services);
_populate(solutions, "applications", applications);
_populate(projects, "services", services);
_populate(applications, "services", services);

/**
 * Return a json object to the response.
 * @param {Number} item the item to return
 * @param {Object} res the http response
 * @param {Function} next the callback function executed if error occurs
 * @private
 */
function _returnItem(item, res, next) {
    if (!item) {
        next(new Error("not found"));
    } else {
        res.json(item);
    }
}

/**
 * Get a solution.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getSolution(req, res, next) {
    _returnItem(solutions[req.params.id], res, next);
}

/**
 * Post a project.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function createProject(req, res, next) {
    res.json(req.params.project);
}

/**
 * Get a project.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getProject(req, res, next) {
    _returnItem(projects[req.params.id], res, next);
}

/**
 * Get all solutions.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getSolutions(req, res, next) {
    res.json(_.values(solutions));
}

/**
 * Get all projects.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getProjects(req, res, next) {
    res.json(_.values(projects));
}

/**
 * Get all applications.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getApplications(req, res, next) {
    res.json(_.values(applications));
}

/**
 * Get all bundles.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getBundles(req, res, next) {
    res.json(_.values(bundles));
}

/**
 * Get all services.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getServices(req, res, next) {
    res.json(_.values(services));
}

/**
 * Get data displayed in header.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getHeader(req, res, next) {
    res.json(header);
}

/**
 * Get dropdown values for new project.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getProjectQuestions(req, res, next) {
    res.json(projectQuestions);
}

/**
 * Get dropdown values for manage view.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getManageValues(req, res, next) {
    res.json(manageValues);
}

/**
 * Get values for marketplace view.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getMarketplaceValues(req, res, next) {
    res.json(marketplaceValues);
}

/**
 * Get a project.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getService(req, res, next) {
    var item = services[req.params.id];
    if (!item) {
        next(new Error("not found"));
    } else {
        item = JSON.parse(JSON.stringify(item));
        _populate([item], "similarSolutions", services);
        res.json(item);
    }
}

/**
 * Get recent solutions.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getRecentSolutions(req, res, next) {
    res.json(projects["1"].services);
}

/**
 * Get recent users.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getRecentUsers(req, res, next) {
    res.json(projects["1"].users);
}

/**
 * Get recent orders.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getRecentOrders(req, res, next) {
    res.json(projects["1"].orderHistory);
}

/**
 * Get alerts.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getAlerts(req, res, next) {
    res.json(alerts);
}

/**
 * Get alert popup for dashboard.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getAlertPopup(req, res, next) {
    res.json(alertPopup);
}

/**
 * Get staff sign in.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function postStaffSignIn(req, res, next) {
  res.json(staffSignIn);
}

function deleteStaffSignOut(req, res, next) {
  res.json();
}

/**
 * Get Current User
 *
 * @param req
 * @param res
 * @param next
 */
function getCurrentUser(req, res, next) {
  res.json(currentUser);
}

module.exports = {
    getSolution: getSolution,
    createProject: createProject,
    getProject: getProject,
    getSolutions: getSolutions,
    getProjects: getProjects,
    getHeader: getHeader,
    getApplications: getApplications,
    getBundles: getBundles,
    getProjectQuestions: getProjectQuestions,
    getManageValues: getManageValues,
    getService: getService,
    getMarketplaceValues: getMarketplaceValues,
    getRecentSolutions: getRecentSolutions,
    getRecentUsers: getRecentUsers,
    getRecentOrders: getRecentOrders,
    getServices: getServices,
    getAlerts: getAlerts,
    getAlertPopup: getAlertPopup,
    staffSignIn: postStaffSignIn,
    staffSignOut: deleteStaffSignOut,
    getCurrentUser: getCurrentUser
};<commit_msg>Missing comment<commit_after>/*
 * Copyright (C) 2014 TopCoder Inc., All Rights Reserved.
 */
"use strict";

/**
 * Represents controller for mock data.
 * @version 1.0
 * @author Sky_
 */

var _ = require("underscore");

// solution entities
var solutions = {
    1: require("../data/solutions/1.json"),
    2: require("../data/solutions/2.json"),
    3: require("../data/solutions/3.json")
};

// project entities
var projects = {
    1: require("../data/projects/1.json"),
    2: require("../data/projects/2.json"),
    3: require("../data/projects/3.json")
};

// service entities
var services = {
    1: require("../data/services/1.json"),
    2: require("../data/services/2.json"),
    3: require("../data/services/3.json"),
    4: require("../data/services/4.json"),
    5: require("../data/services/5.json"),
    6: require("../data/services/6.json"),
    7: require("../data/services/7.json"),
    8: require("../data/services/8.json"),
    9: require("../data/services/9.json"),
    10: require("../data/services/10.json"),
    11: require("../data/services/11.json"),
    12: require("../data/services/12.json"),
    13: require("../data/services/13.json"),
    14: require("../data/services/14.json"),
    15: require("../data/services/15.json")
};

// application entities
var applications = {
    1: require("../data/applications/1.json"),
    2: require("../data/applications/2.json"),
    3: require("../data/applications/3.json"),
    4: require("../data/applications/4.json")
};

// bundle entities
var bundles = {
    1: require("../data/bundles/1.json"),
    2: require("../data/bundles/2.json"),
    3: require("../data/bundles/3.json")
};

// all data displayed in header
var header = require("../data/header.json");

// dropdown values for new project
var projectQuestions = require("../data/project_questions.json");

// dropdown values for manage view
var manageValues = require("../data/manage.json");

// values for marketplace
var marketplaceValues = require("../data/marketplace.json");

// alerts for dashboard and manage
var alerts = require("../data/alerts.json");

// alerts with x icon for dashboard
var alertPopup = require("../data/alert-popup.json");

var staffSignIn = require("../data/staff/sign_in.json");

var currentUser = require("../data/current_user.json");

/**
 * Populate references.
 * @param {Object} target the elements to populate (hashmap id to element)
 * @param {String} fieldName the name of the field to be populated
 * @param {Object} source the referenced elements (hashmap id to element)
 * @private
 */
function _populate(target, fieldName, source) {
    _.each(target, function (item) {
        item[fieldName] = _.map(item[fieldName], function (id) {
            return source[id];
        });
    });
}

_populate(solutions, "projects", projects);
_populate(solutions, "services", services);
_populate(solutions, "applications", applications);
_populate(projects, "services", services);
_populate(applications, "services", services);

/**
 * Return a json object to the response.
 * @param {Number} item the item to return
 * @param {Object} res the http response
 * @param {Function} next the callback function executed if error occurs
 * @private
 */
function _returnItem(item, res, next) {
    if (!item) {
        next(new Error("not found"));
    } else {
        res.json(item);
    }
}

/**
 * Get a solution.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getSolution(req, res, next) {
    _returnItem(solutions[req.params.id], res, next);
}

/**
 * Post a project.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function createProject(req, res, next) {
    res.json(req.params.project);
}

/**
 * Get a project.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getProject(req, res, next) {
    _returnItem(projects[req.params.id], res, next);
}

/**
 * Get all solutions.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getSolutions(req, res, next) {
    res.json(_.values(solutions));
}

/**
 * Get all projects.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getProjects(req, res, next) {
    res.json(_.values(projects));
}

/**
 * Get all applications.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getApplications(req, res, next) {
    res.json(_.values(applications));
}

/**
 * Get all bundles.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getBundles(req, res, next) {
    res.json(_.values(bundles));
}

/**
 * Get all services.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getServices(req, res, next) {
    res.json(_.values(services));
}

/**
 * Get data displayed in header.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getHeader(req, res, next) {
    res.json(header);
}

/**
 * Get dropdown values for new project.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getProjectQuestions(req, res, next) {
    res.json(projectQuestions);
}

/**
 * Get dropdown values for manage view.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getManageValues(req, res, next) {
    res.json(manageValues);
}

/**
 * Get values for marketplace view.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getMarketplaceValues(req, res, next) {
    res.json(marketplaceValues);
}

/**
 * Get a project.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getService(req, res, next) {
    var item = services[req.params.id];
    if (!item) {
        next(new Error("not found"));
    } else {
        item = JSON.parse(JSON.stringify(item));
        _populate([item], "similarSolutions", services);
        res.json(item);
    }
}

/**
 * Get recent solutions.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getRecentSolutions(req, res, next) {
    res.json(projects["1"].services);
}

/**
 * Get recent users.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getRecentUsers(req, res, next) {
    res.json(projects["1"].users);
}

/**
 * Get recent orders.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getRecentOrders(req, res, next) {
    res.json(projects["1"].orderHistory);
}

/**
 * Get alerts.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getAlerts(req, res, next) {
    res.json(alerts);
}

/**
 * Get alert popup for dashboard.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function getAlertPopup(req, res, next) {
    res.json(alertPopup);
}

/**
 * Staff Sign In.
 * @param {Object} req the request object
 * @param {Object} res the response object
 * @param {Function} next the callback function
 */
function postStaffSignIn(req, res, next) {
  res.json(staffSignIn);
}

/**
 * Staff Sign Out.
 * @param req
 * @param res
 * @param next
 */
function deleteStaffSignOut(req, res, next) {
  res.json();
}

/**
 * Get Current User
 *
 * @param req
 * @param res
 * @param next
 */
function getCurrentUser(req, res, next) {
  res.json(currentUser);
}

module.exports = {
    getSolution: getSolution,
    createProject: createProject,
    getProject: getProject,
    getSolutions: getSolutions,
    getProjects: getProjects,
    getHeader: getHeader,
    getApplications: getApplications,
    getBundles: getBundles,
    getProjectQuestions: getProjectQuestions,
    getManageValues: getManageValues,
    getService: getService,
    getMarketplaceValues: getMarketplaceValues,
    getRecentSolutions: getRecentSolutions,
    getRecentUsers: getRecentUsers,
    getRecentOrders: getRecentOrders,
    getServices: getServices,
    getAlerts: getAlerts,
    getAlertPopup: getAlertPopup,
    staffSignIn: postStaffSignIn,
    staffSignOut: deleteStaffSignOut,
    getCurrentUser: getCurrentUser
};<|endoftext|>


<commit_before>/*
This file is part of the Juju GUI, which lets users view and manage Juju
environments within a graphical interface (https://launchpad.net/juju-gui).
Copyright (C) 2012-2013 Canonical Ltd.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License version 3, as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
General Public License for more details.

You should have received a copy of the GNU Affero General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

'use strict';

YUI.add('search-results', function(Y) {

  juju.components.SearchResults = React.createClass({
    searchXhr: null,
    template: Handlebars.templates['search-results-tmpl.hbs'],

     /**
      If it's the same charm but for different series, collapse into one
      entity. We do this by converting the list to an OrderedDict, keyed on
      the match criteria (name, owner, type). When there is a key collision,
      add the series to the exist entity. Using an OrderedDict (versus a
      normal dict) is important to preserve sorting.

      @method collapseSeries
      @param {Array} entities The entities in their uncollapsed state.
     */
    collapseSeries: function(entities) {

      function seriesKey(series) {
        // XXX kadams54, 2015-05-21: This series mapping needs to be updated
        // with each release, at least until we can figure out a better way.
        // XXX urosj, 2015-11-04: We need to support all series, not just
        // Ubuntu ones.
        return {
          precise: 12.04,
          trusty:  14.04,
          utopic:  14.10,
          vivid:   15.04,
          wily:    15.10
        }[series.name];
      }

      function entityKey(entity) {
        return [entity.name, entity.owner, entity.type, entity.promulgated];
      }

      var collapsedEntities = {},
          orderedKeys = [];
      for (var i = 0, l = entities.length; i < l; i++) {
        var entity = entities[i],
            key = entityKey(entity),
            series = entity.series,
            url = entity.url || '',
            value = {name: series, url: url};
        // If the key already exists, append the series to the existing list.
        if (collapsedEntities[key]) {
          var collapsed = collapsedEntities[key];
          // Aggregate downloads across different series.
          collapsed.downloads += entity.downloads || 0;
          // Add series to the list.
          collapsed.series.push(value);
          // Ensure that the most recent series is first.
          collapsed.series.sort(function(a, b) {
            var k1 = seriesKey(a),
                k2 = seriesKey(b);
            // We want a reverse sort, so...
            return k2 - k1;
          });
          // De-dupe the series array.
          collapsed.series = collapsed.series.filter(function(s, pos, arry) {
            return !pos || s.name != arry[pos - 1].name;
          });
          // And that its URL is used for the entity.
          collapsed.url = collapsed.series[0].url;
        } else {
          // Convert all series attributes in the entities to lists.
          if (series) {
            entity.series = [value];
          } else {
            entity.series = [];
          }
          // Ensure downloads and URL are present.
          entity.downloads = entity.downloads || 0;
          entity.url = entity.url || '';
          entity.id = entity.series.length > 0 ?
              entity.series[0].name + '/' + entity.name : entity.name;
          collapsedEntities[key] = entity;
          // Save the key so we can preserve sort order.
          orderedKeys.push(key);
        }
      }
      // Now convert that object back to an ordered list and return it.
      var returnedEntities = [];
      for (var i = 0, l = orderedKeys.length; i < l; i++) {
        var k = orderedKeys[i];
        returnedEntities.push(collapsedEntities[k]);
      }
      return returnedEntities;
    },

    /**
      Handle successful searches by updating internal state with the results.

      @method searchSuccess
      @param {Array} rawResults The entity models returned by the search.
    */
    searchSuccess: function(rawResults) {
      // Parse the raw results.
      var results = rawResults.map(function(model) {
        return model.toEntity();
      }, this);
      var activeComponent;
      results = this.collapseSeries(results);
      // Split the results into promulgated and normal.
      var promulgatedResults = [],
          normalResults = [];
      results.forEach(function(obj) {
        // Pass in a full id including the owner to allow looking up the entity.
        obj.storeId = '~' + obj.owner + '/' + obj.id;
        if (obj.promulgated) {
          promulgatedResults.push(obj);
        } else {
          normalResults.push(obj);
        }
      });
      if (results.length === 0) {
        activeComponent = 'no-results';
      } else {
        activeComponent = 'search-results';
      }
      var data = {
        text: this.props.query,
        solutionsCount: results.length,
        normalResultsCount: normalResults.length,
        normalResults: normalResults,
        promulgatedResultsCount: promulgatedResults.length,
        promulgatedResults: promulgatedResults
      };
      // These need to be set separately, seemingly due to a React quirk.
      this.setState({waitingForSearch: false});
      this.setState({data: data});
      this._changeActiveComponent(activeComponent);
    },

    /**
      Handle failed searches by displaying appropriate error notification.

      @method searchFailure
      @param {Object} response The failure response.
    */
    searchFailure: function(response) {
      // XXX: Implement error handling.
      console.error('Search request failed.');
    },

    /**
      Search the charmstore with the given filters.

      @method searchRequest
      @param {String} query The text to search for.
      @param {String} tags The tags to limit the search by.
    */
    searchRequest: function(query, tags, type) {
      this._changeActiveComponent('loading');
      this.setState({ waitingForSearch: true });
      this.searchXhr = this.props.charmstoreSearch(
        {text: query, tags: tags, type: type},
        this.searchSuccess,
        this.searchFailure,
        150
      );
    },

    /**
      Determines whether an API search request is actually needed. We only need
      to make a new search request if the query has changed since the last one.

      @method shouldSearch
      @param {Object} nextProps The next set of properties.
    */
    shouldSearch: function(nextProps) {
      if (!this.state.data || !this.state.data.text) {
        return true;
      }
      var nextQuery = JSON.stringify(nextProps.query),
          currentQuery = JSON.stringify(this.state.data.text);
      return nextQuery !== currentQuery;
    },

    getInitialState: function() {
      var state = this.generateState(this.props);
      state.waitingForSearch = false;
      return state;
    },

    componentDidMount: function() {
      this.searchRequest(this.props.query, this.props.tags, this.props.type);
    },

    componentWillUnmount: function() {
      this.searchXhr.abort();
    },

    componentWillReceiveProps: function(nextProps) {
      if (this.shouldSearch(nextProps)) {
        this.searchRequest(nextProps.query, this.props.tags, this.props.type);
      }
    },

    shouldComponentUpdate: function(nextProps, nextState) {
      return this.state.activeComponent !== 'loading' ||
          this.shouldSearch(nextProps) && !this.state.waitingForSearch;
    },

    /**
      Generates the state for the search results.

      @method generateState
      @param {Object} nextProps The props which were sent to the component.
      @return {Object} A generated state object which can be passed to setState.
    */
    generateState: function(nextProps) {
      var state = {
        activeComponent: nextProps.activeComponent || 'loading'
      };
      var currentType = nextProps.type !== undefined ?
          nextProps.type : this.props.type;
      switch (state.activeComponent) {
        case 'loading':
          state.activeChild = {
            component:

                <juju.components.Spinner />

          };
          break;
        case 'search-results':
          var data = this.state.data;
          var html = this.template(data);
          state.activeChild = {
            component:

                  {this._generateResultsMessage(data.text, data.solutionsCount)}

                    <juju.components.SearchResultsTypeFilter
                      changeState={this.props.changeState}
                      currentType={currentType} />

                        <form>

                            Sort by:
                            <select>
                              <option value="-downloads">Most popular</option>
                              <option value="downloads">Least popular</option>
                              <option value="name">Name (a-z)</option>
                              <option value="-name">Name (z-a)</option>
                              <option value="owner">Author (a-z)</option>
                              <option value="-owner">Author (z-a)</option>
                            </select>

                            Series:
                            <select>
                              <option>None</option>
                            </select>

                        </form>

          };
          break;
        case 'no-results':
          state.activeChild = {
            component:

                  Your search for {this.state.data.text}
                  {' '}
                  returned 0 results

                  Try a more specific or different query, try other keywords or
                  learn how to
                  {' '}

                    create your own solution
                  .

          };
          break;
      }
      return state;
    },

    /**
      Change the state to reflect the chosen component.

      @method _changeActiveComponent
      @param {String} newComponent The component to switch to.
    */
    _changeActiveComponent: function(newComponent) {
      var nextProps = this.state;
      nextProps.activeComponent = newComponent;
      this.setState(this.generateState(nextProps));
    },

    /**
      Display a search results message if there is search text.

      @method _generateResultsMessage
      @param {String} text The search text.
      @param {Integer} solutionsCount The number of search results.
    */
    _generateResultsMessage: function(text, solutionsCount) {
      if (text) {
        return (

            Your search for ‘{text}’ returned {solutionsCount}{' '}
            results.

        );
      }
      return;
    },

    /**
      Handle any clicks inside the template and route them to the correct
      handler.

      @method _handleTemplateClicks
      @param {Object} e The click event
    */
    _handleTemplateClicks: function(e) {
      e.preventDefault();
      var target = e.target;
      var className = target.className;
      if (className.indexOf('list-block__entity-link') > -1) {
        this._handleEntityClick(target);
      }
    },

    /**
      Show the entity details when clicked.

      @method _handleEntityClick
      @param {Object} target The element that was clicked
    */
    _handleEntityClick: function(target) {
      this.props.changeState({
        sectionC: {
          component: 'charmbrowser',
          metadata: {
            activeComponent: 'entity-details',
            id: target.getAttribute('data-id')
          }
        }
      });
    },

    /**
      Generate the base classes from on the props.

      @method _generateClasses
      @returns {String} The collection of class names.
    */
    _generateClasses: function() {
      return classNames(
        'search-results',
        this.props.inline ? '' : 'search-results--floating'
      );
    },

    render: function() {
      return (

          {this.state.activeChild.component}

      );
    }
  });

}, '0.1.0', {requires: [
  'loading-spinner',
  'search-results-type-filter'
]});
<commit_msg>Do a new search when the type filter changes.<commit_after>/*
This file is part of the Juju GUI, which lets users view and manage Juju
environments within a graphical interface (https://launchpad.net/juju-gui).
Copyright (C) 2012-2013 Canonical Ltd.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License version 3, as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
General Public License for more details.

You should have received a copy of the GNU Affero General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

'use strict';

YUI.add('search-results', function(Y) {

  juju.components.SearchResults = React.createClass({
    searchXhr: null,
    template: Handlebars.templates['search-results-tmpl.hbs'],

     /**
      If it's the same charm but for different series, collapse into one
      entity. We do this by converting the list to an OrderedDict, keyed on
      the match criteria (name, owner, type). When there is a key collision,
      add the series to the exist entity. Using an OrderedDict (versus a
      normal dict) is important to preserve sorting.

      @method collapseSeries
      @param {Array} entities The entities in their uncollapsed state.
     */
    collapseSeries: function(entities) {

      function seriesKey(series) {
        // XXX kadams54, 2015-05-21: This series mapping needs to be updated
        // with each release, at least until we can figure out a better way.
        // XXX urosj, 2015-11-04: We need to support all series, not just
        // Ubuntu ones.
        return {
          precise: 12.04,
          trusty:  14.04,
          utopic:  14.10,
          vivid:   15.04,
          wily:    15.10
        }[series.name];
      }

      function entityKey(entity) {
        return [entity.name, entity.owner, entity.type, entity.promulgated];
      }

      var collapsedEntities = {},
          orderedKeys = [];
      for (var i = 0, l = entities.length; i < l; i++) {
        var entity = entities[i],
            key = entityKey(entity),
            series = entity.series,
            url = entity.url || '',
            value = {name: series, url: url};
        // If the key already exists, append the series to the existing list.
        if (collapsedEntities[key]) {
          var collapsed = collapsedEntities[key];
          // Aggregate downloads across different series.
          collapsed.downloads += entity.downloads || 0;
          // Add series to the list.
          collapsed.series.push(value);
          // Ensure that the most recent series is first.
          collapsed.series.sort(function(a, b) {
            var k1 = seriesKey(a),
                k2 = seriesKey(b);
            // We want a reverse sort, so...
            return k2 - k1;
          });
          // De-dupe the series array.
          collapsed.series = collapsed.series.filter(function(s, pos, arry) {
            return !pos || s.name != arry[pos - 1].name;
          });
          // And that its URL is used for the entity.
          collapsed.url = collapsed.series[0].url;
        } else {
          // Convert all series attributes in the entities to lists.
          if (series) {
            entity.series = [value];
          } else {
            entity.series = [];
          }
          // Ensure downloads and URL are present.
          entity.downloads = entity.downloads || 0;
          entity.url = entity.url || '';
          entity.id = entity.series.length > 0 ?
              entity.series[0].name + '/' + entity.name : entity.name;
          collapsedEntities[key] = entity;
          // Save the key so we can preserve sort order.
          orderedKeys.push(key);
        }
      }
      // Now convert that object back to an ordered list and return it.
      var returnedEntities = [];
      for (var i = 0, l = orderedKeys.length; i < l; i++) {
        var k = orderedKeys[i];
        returnedEntities.push(collapsedEntities[k]);
      }
      return returnedEntities;
    },

    /**
      Handle successful searches by updating internal state with the results.

      @method searchSuccess
      @param {Array} rawResults The entity models returned by the search.
    */
    searchSuccess: function(rawResults) {
      // Parse the raw results.
      var results = rawResults.map(function(model) {
        return model.toEntity();
      }, this);
      var activeComponent;
      results = this.collapseSeries(results);
      // Split the results into promulgated and normal.
      var promulgatedResults = [],
          normalResults = [];
      results.forEach(function(obj) {
        // Pass in a full id including the owner to allow looking up the entity.
        obj.storeId = '~' + obj.owner + '/' + obj.id;
        if (obj.promulgated) {
          promulgatedResults.push(obj);
        } else {
          normalResults.push(obj);
        }
      });
      if (results.length === 0) {
        activeComponent = 'no-results';
      } else {
        activeComponent = 'search-results';
      }
      var data = {
        text: this.props.query,
        solutionsCount: results.length,
        normalResultsCount: normalResults.length,
        normalResults: normalResults,
        promulgatedResultsCount: promulgatedResults.length,
        promulgatedResults: promulgatedResults
      };
      // These need to be set separately, seemingly due to a React quirk.
      this.setState({waitingForSearch: false});
      this.setState({data: data});
      this._changeActiveComponent(activeComponent);
    },

    /**
      Handle failed searches by displaying appropriate error notification.

      @method searchFailure
      @param {Object} response The failure response.
    */
    searchFailure: function(response) {
      // XXX: Implement error handling.
      console.error('Search request failed.');
    },

    /**
      Search the charmstore with the given filters.

      @method searchRequest
      @param {String} query The text to search for.
      @param {String} tags The tags to limit the search by.
    */
    searchRequest: function(query, tags, type) {
      var filters = {text: query, tags: tags};
      // Don't add the type property unless required otherwise the API will
      // filter by charm.
      if (type) {
        filters.type = type;
      }
      this._changeActiveComponent('loading');
      this.setState({ waitingForSearch: true });
      this.searchXhr = this.props.charmstoreSearch(
        filters,
        this.searchSuccess,
        this.searchFailure,
        150
      );
    },

    /**
      Determines whether an API search request is actually needed. We only need
      to make a new search request if the query has changed since the last one.

      @method shouldSearch
      @param {Object} nextProps The next set of properties.
    */
    shouldSearch: function(nextProps) {
      if (!this.state.data || !this.state.data.text) {
        return true;
      }
      var nextQuery = JSON.stringify(nextProps.query),
          currentQuery = JSON.stringify(this.state.data.text);
      return nextQuery !== currentQuery || nextProps.type !== this.props.type;
    },

    getInitialState: function() {
      var state = this.generateState(this.props);
      state.waitingForSearch = false;
      return state;
    },

    componentDidMount: function() {
      this.searchRequest(this.props.query, this.props.tags, this.props.type);
    },

    componentWillUnmount: function() {
      this.searchXhr.abort();
    },

    componentWillReceiveProps: function(nextProps) {
      if (this.shouldSearch(nextProps)) {
        this.searchRequest(nextProps.query, nextProps.tags, nextProps.type);
      }
    },

    shouldComponentUpdate: function(nextProps, nextState) {
      return this.state.activeComponent !== 'loading' ||
          this.shouldSearch(nextProps) && !this.state.waitingForSearch;
    },

    /**
      Generates the state for the search results.

      @method generateState
      @param {Object} nextProps The props which were sent to the component.
      @return {Object} A generated state object which can be passed to setState.
    */
    generateState: function(nextProps) {
      var state = {
        activeComponent: nextProps.activeComponent || 'loading'
      };
      var currentType = nextProps.type !== undefined ?
          nextProps.type : this.props.type;
      switch (state.activeComponent) {
        case 'loading':
          state.activeChild = {
            component:

                <juju.components.Spinner />

          };
          break;
        case 'search-results':
          var data = this.state.data;
          var html = this.template(data);
          state.activeChild = {
            component:

                  {this._generateResultsMessage(data.text, data.solutionsCount)}

                    <juju.components.SearchResultsTypeFilter
                      changeState={this.props.changeState}
                      currentType={currentType} />

                        <form>

                            Sort by:
                            <select>
                              <option value="-downloads">Most popular</option>
                              <option value="downloads">Least popular</option>
                              <option value="name">Name (a-z)</option>
                              <option value="-name">Name (z-a)</option>
                              <option value="owner">Author (a-z)</option>
                              <option value="-owner">Author (z-a)</option>
                            </select>

                            Series:
                            <select>
                              <option>None</option>
                            </select>

                        </form>

          };
          break;
        case 'no-results':
          state.activeChild = {
            component:

                  Your search for {this.state.data.text}
                  {' '}
                  returned 0 results

                  Try a more specific or different query, try other keywords or
                  learn how to
                  {' '}

                    create your own solution
                  .

          };
          break;
      }
      return state;
    },

    /**
      Change the state to reflect the chosen component.

      @method _changeActiveComponent
      @param {String} newComponent The component to switch to.
    */
    _changeActiveComponent: function(newComponent) {
      var nextProps = this.state;
      nextProps.activeComponent = newComponent;
      this.setState(this.generateState(nextProps));
    },

    /**
      Display a search results message if there is search text.

      @method _generateResultsMessage
      @param {String} text The search text.
      @param {Integer} solutionsCount The number of search results.
    */
    _generateResultsMessage: function(text, solutionsCount) {
      if (text) {
        return (

            Your search for ‘{text}’ returned {solutionsCount}{' '}
            results.

        );
      }
      return;
    },

    /**
      Handle any clicks inside the template and route them to the correct
      handler.

      @method _handleTemplateClicks
      @param {Object} e The click event
    */
    _handleTemplateClicks: function(e) {
      e.preventDefault();
      var target = e.target;
      var className = target.className;
      if (className.indexOf('list-block__entity-link') > -1) {
        this._handleEntityClick(target);
      }
    },

    /**
      Show the entity details when clicked.

      @method _handleEntityClick
      @param {Object} target The element that was clicked
    */
    _handleEntityClick: function(target) {
      this.props.changeState({
        sectionC: {
          component: 'charmbrowser',
          metadata: {
            activeComponent: 'entity-details',
            id: target.getAttribute('data-id')
          }
        }
      });
    },

    /**
      Generate the base classes from on the props.

      @method _generateClasses
      @returns {String} The collection of class names.
    */
    _generateClasses: function() {
      return classNames(
        'search-results',
        this.props.inline ? '' : 'search-results--floating'
      );
    },

    render: function() {
      return (

          {this.state.activeChild.component}

      );
    }
  });

}, '0.1.0', {requires: [
  'loading-spinner',
  'search-results-type-filter'
]});
<|endoftext|>