<commit_before>/**
 * Copyright 2017 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

const fetch = require('node-fetch'); // polyfill
const minimist = require('minimist');

const CI_HOST = process.env.CI_HOST || 'https://lighthouse-ci.appspot.com';
const API_KEY = process.env.LIGHTHOUSE_API_KEY || process.env.API_KEY;
const RUNNERS = {chrome: 'chrome', wpt: 'wpt'};

if (process.env.API_KEY) {
  console.log('Warning:
The environment variable API_KEY is deprecated.
Please use LIGHTHOUSE_API_KEY instead.');
}

function printUsageAndExit() {
  const usage = `Usage:
runLighthouse.js [--score=<score>] [--no-comment] [--runner=${Object.keys(RUNNERS)}] <url>

Options:
  --score      Minimum score for the pull request to be considered "passing".
               If omitted, merging the PR will be allowed no matter what the score. [Number]

  --no-comment Doesn't post a comment to the PR issue summarizing the Lighthouse results. [Boolean]

  --runner     Selects Lighthouse running on Chrome or WebPageTest. [--runner=${Object.keys(RUNNERS)}]

  --help       Prints help.

Examples:

  Runs Lighthouse and posts a summary of the results.
    runLighthouse.js https://example.com

  Fails the PR if the score drops below 93. Posts the summary comment.
    runLighthouse.js --score=93 https://example.com

  Runs Lighthouse on WebPageTest. Fails the PR if the score drops below 93.
    runLighthouse.js --score=93 --runner=wpt --no-comment https://example.com`;

  console.log(usage);
  process.exit(1);
}

/**
 * Collects command lines flags and creates settings to run LH CI.
 * @return {!Object} Settings object.
 */
function getConfig() {
  const args = process.argv.slice(2);
  const argv = minimist(args, {
    boolean: ['comment', 'help'],
    default: {comment: true},
    alias: {help: 'h'}
  });
  const config = {};

  if (argv.help) {
    printUsageAndExit();
  }

  config.testUrl = argv._[0];
  if (!config.testUrl) {
    console.log('Please provide a url to test.');
    printUsageAndExit();
  }

  config.addComment = argv.comment;
  config.minPassScore = Number(argv.score);
  if (!config.addComment && !config.minPassScore) {
    console.log('Please provide a --score when using --no-comment.');
    printUsageAndExit();
  }

  config.runner = argv.runner || RUNNERS.chrome;
  const possibleRunners = Object.keys(RUNNERS);
  if (!possibleRunners.includes(config.runner)) {
    console.log(
        `Unknown runner "${config.runner}". Options: ${possibleRunners}`);
    printUsageAndExit();
  }
  console.log(`Using runner: ${config.runner}`);

  config.pr = {
    number: parseInt(process.env.TRAVIS_PULL_REQUEST, 10),
    sha: process.env.TRAVIS_PULL_REQUEST_SHA
  };

  const repoSlug = process.env.TRAVIS_PULL_REQUEST_SLUG;
  config.repo = {
    owner: repoSlug.split('/')[0],
    name: repoSlug.split('/')[1]
  };

  return config;
}

/**
 * @param {!Object} config Settings to run the Lighthouse CI.
 */
function run(config) {
  let endpoint;
  let body = JSON.stringify(config);

  switch (config.runner) {
    case RUNNERS.wpt:
      endpoint = `${CI_HOST}/run_on_wpt`;
      break;
    case RUNNERS.chrome: // same as default
    default:
      endpoint = `${CI_HOST}/run_on_chrome`;
      body = JSON.stringify(Object.assign({format: 'json'}, config));
  }

  fetch(endpoint, {method: 'POST', body, headers: {
    'Content-Type': 'application/json',
    'X-API-KEY': API_KEY
  }})
  .then(resp => resp.json())
  .then(json => {
    if (config.runner === RUNNERS.wpt) {
      console.log(
          `Started Lighthouse run on WebPageTest: ${json.data.target_url}`);
      return;
    }
    console.log('Lighthouse CI score:', json.score);
  })
  .catch(err => {
    console.log('Lighthouse CI failed', err);
    process.exit(1);
  });
}

// Run LH if this is a PR.
const config = getConfig();
if (process.env.TRAVIS_EVENT_TYPE === 'pull_request') {
  run(config);
} else {
  console.log('Lighthouse is not run for non-PR commits.');
}
<commit_msg>remove line breaks from console.log<commit_after>/**
 * Copyright 2017 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

const fetch = require('node-fetch'); // polyfill
const minimist = require('minimist');

const CI_HOST = process.env.CI_HOST || 'https://lighthouse-ci.appspot.com';
const API_KEY = process.env.LIGHTHOUSE_API_KEY || process.env.API_KEY;
const RUNNERS = {chrome: 'chrome', wpt: 'wpt'};

if (process.env.API_KEY) {
  console.log('Warning: The environment variable API_KEY is deprecated. Please use LIGHTHOUSE_API_KEY instead.');
}

function printUsageAndExit() {
  const usage = `Usage:
runLighthouse.js [--score=<score>] [--no-comment] [--runner=${Object.keys(RUNNERS)}] <url>

Options:
  --score      Minimum score for the pull request to be considered "passing".
               If omitted, merging the PR will be allowed no matter what the score. [Number]

  --no-comment Doesn't post a comment to the PR issue summarizing the Lighthouse results. [Boolean]

  --runner     Selects Lighthouse running on Chrome or WebPageTest. [--runner=${Object.keys(RUNNERS)}]

  --help       Prints help.

Examples:

  Runs Lighthouse and posts a summary of the results.
    runLighthouse.js https://example.com

  Fails the PR if the score drops below 93. Posts the summary comment.
    runLighthouse.js --score=93 https://example.com

  Runs Lighthouse on WebPageTest. Fails the PR if the score drops below 93.
    runLighthouse.js --score=93 --runner=wpt --no-comment https://example.com`;

  console.log(usage);
  process.exit(1);
}

/**
 * Collects command lines flags and creates settings to run LH CI.
 * @return {!Object} Settings object.
 */
function getConfig() {
  const args = process.argv.slice(2);
  const argv = minimist(args, {
    boolean: ['comment', 'help'],
    default: {comment: true},
    alias: {help: 'h'}
  });
  const config = {};

  if (argv.help) {
    printUsageAndExit();
  }

  config.testUrl = argv._[0];
  if (!config.testUrl) {
    console.log('Please provide a url to test.');
    printUsageAndExit();
  }

  config.addComment = argv.comment;
  config.minPassScore = Number(argv.score);
  if (!config.addComment && !config.minPassScore) {
    console.log('Please provide a --score when using --no-comment.');
    printUsageAndExit();
  }

  config.runner = argv.runner || RUNNERS.chrome;
  const possibleRunners = Object.keys(RUNNERS);
  if (!possibleRunners.includes(config.runner)) {
    console.log(
        `Unknown runner "${config.runner}". Options: ${possibleRunners}`);
    printUsageAndExit();
  }
  console.log(`Using runner: ${config.runner}`);

  config.pr = {
    number: parseInt(process.env.TRAVIS_PULL_REQUEST, 10),
    sha: process.env.TRAVIS_PULL_REQUEST_SHA
  };

  const repoSlug = process.env.TRAVIS_PULL_REQUEST_SLUG;
  config.repo = {
    owner: repoSlug.split('/')[0],
    name: repoSlug.split('/')[1]
  };

  return config;
}

/**
 * @param {!Object} config Settings to run the Lighthouse CI.
 */
function run(config) {
  let endpoint;
  let body = JSON.stringify(config);

  switch (config.runner) {
    case RUNNERS.wpt:
      endpoint = `${CI_HOST}/run_on_wpt`;
      break;
    case RUNNERS.chrome: // same as default
    default:
      endpoint = `${CI_HOST}/run_on_chrome`;
      body = JSON.stringify(Object.assign({format: 'json'}, config));
  }

  fetch(endpoint, {method: 'POST', body, headers: {
    'Content-Type': 'application/json',
    'X-API-KEY': API_KEY
  }})
  .then(resp => resp.json())
  .then(json => {
    if (config.runner === RUNNERS.wpt) {
      console.log(
          `Started Lighthouse run on WebPageTest: ${json.data.target_url}`);
      return;
    }
    console.log('Lighthouse CI score:', json.score);
  })
  .catch(err => {
    console.log('Lighthouse CI failed', err);
    process.exit(1);
  });
}

// Run LH if this is a PR.
const config = getConfig();
if (process.env.TRAVIS_EVENT_TYPE === 'pull_request') {
  run(config);
} else {
  console.log('Lighthouse is not run for non-PR commits.');
}
<|endoftext|>


<commit_before>var fs = require('fs'),
    vows = require('vows'),
    assert = require('assert'),
    nodemock = require('nodemock'),
    sqlite3 = require('sqlite3');

var db = require('../lib/db.js')

function db_file_setup(){
  var test_db_filename = 'db/test.db'
  if(fs.existsSync(test_db_filename)){
    fs.unlinkSync(test_db_filename)
  }
  db.setup(sqlite3, test_db_filename)
}

db_file_setup()

vows.describe('db').addBatch({
  'sqlite3': {
    topic: db,
    'setup': function(db){
      assert(db.connected)
    }
  },
  'missing load_block_height': {
    topic: function(){
      db.load_block_height(this.callback)
    },
    'no height': function(height){
      assert.isUndefined(height)
    }
  },
  'existing load_block_height': {
    topic: function(){
      db.save_block_height(1, function(){
        console.log("saveback!")
        db.load_block_height(this.callback)
      })
    },
    'existing height': function(height){
      assert.equal(height, 1)
    },
  }

}).export(module)
<commit_msg>strange test failures<commit_after>var fs = require('fs'),
    vows = require('vows'),
    assert = require('assert'),
    nodemock = require('nodemock'),
    sqlite3 = require('sqlite3');

var db = require('../lib/db.js')

function db_file_setup(){
  var test_db_filename = 'db/test.db'
  if(fs.existsSync(test_db_filename)){
    fs.unlinkSync(test_db_filename)
  }
  db.setup(sqlite3, test_db_filename)
}

db_file_setup()

vows.describe('db').addBatch({
  'sqlite3': {
    topic: db,
    'setup': function(db){
      assert(db.connected)
    }
  },
  'missing load_block_height': {
    topic: function(){
      db.load_block_height(this.callback)
    },
    'no height': function(height){
      assert.isUndefined(height)
    }
  },
  'existing load_block_height': {
    topic: function(){
      db.save_block_height(1, function(){
        db.load_block_height(this.callback)
      })
    },
    'existing height': function(height){
      assert.equal(height, 1)
    }
  },
  'save_block_height': {
    topic: function(){
      db.save_block_height(1, this.callback)
    },
    'saved': function(height){
      assert(true)
    },
  }

}).export(module)
<|endoftext|>


<commit_before>'use strict'
module.exports = getFic
var Bluebird = require('bluebird')
var Site = require('./site.js')
var cheerio = require('cheerio')
var chapterFilename = require('./chapter-filename.js')
var Readable = require('readable-stream').Readable
var inherits = require('util').inherits
var FicStream = require('./fic-stream.js')

function concurrently (_todo, concurrency, forEach) {
  var todo = Object.assign([], _todo)
  var run = 0
  var active = 0
  var aborted = false
  return new Bluebird((resolve, reject) => {
    function runNext () {
      if (aborted) return
      if (active === 0 && todo.length === 0) return resolve()
      while (active < concurrency && todo.length) {
        ++active
        forEach(todo.shift(), run++).then(() => {
          --active
          runNext()
          return null
        }).catch(err => {
          aborted = true
          reject(err)
        })
      }
    }
    runNext()
  })
}

function rewriteLinks (fic, chapter, handleLink) {
  var $ = cheerio.load(chapter.content)
  $('a').each((ii, a) => {
    var $a = $(a)
    var startAs = $a.attr('href')
    if (!startAs) {
      $a.remove()
      return
    }
    var href = fic.normalizeLink(startAs, chapter.base)
    var newHref = handleLink(href, $a)
    $a.attr('href', newHref || href)
  })
  chapter.content = $.html()
}

function rewriteImages (fic, chapter, handleImage) {
  var $ = cheerio.load(chapter.content)
  $('img').each((ii, img) => {
    var $img = $(img)
    var startAs = $img.attr('src')
    if (!startAs) return
    var src = fic.normalizeLink(startAs, chapter.base)
    var newsrc = handleImage(src, $img)
    $img.attr('src', newsrc || src)
  })
  chapter.content = $.html()
}

function findChapter (href, fic) {
  var matching = fic.chapters.filter(index => fic.normalizeLink(index.link) === fic.normalizeLink(href))
  return matching && matching[0]
}

function inlineImages (images) {
  return (src, $img) => {
    if (/clear[.]png$/.test(src)) return
    if (!images[src]) {
      var ext = src.match(/([.](?:jpe?g|gif|png))/)
      ext = ext && ext[1]
      if (ext === '.jpeg') ext = '.jpg'
      images[src] = {
        filename: 'image-' + (Object.keys(images).length + 1) + (ext || '.guess.jpg')
      }
    }
    return images[src].filename
  }
}

function linklocalChapters (fic, externals) {
  return (href, $a, orElse) => {
    if (!orElse) orElse = () => { }
    if ($a.text() === '↑') {
      $a.remove()
      return
    }
    var linkedChapter = findChapter(href, fic)
    if (linkedChapter) {
      return chapterFilename(linkedChapter)
    } else if (externals[href]) {
      return externals[href].filename
    } else {
      return orElse(href) || href
    }
  }
}

function getFic (fetch, fic, maxConcurrency) {
  if (!maxConcurrency) maxConcurrency = 4
  var stream = new FicStream({highWaterMark: maxConcurrency * 2})
  var externals = {}
  var images = {}
  var chapters = fic.chapters

  concurrently(chapters, maxConcurrency, (chapterInfo) => {
    return fic.getChapter(fetch, chapterInfo.link).then((chapter) => {
      chapter.order = chapterInfo.order
      chapter.name = chapterInfo.name
      rewriteImages(fic, chapter, inlineImages(images))
      rewriteLinks(fic, chapter, (href, $a) => {
        return linklocalChapters(fic, externals)(href, $a, (href) => {
          if (!chapterInfo.externals) return
          try {
            var site = Site.fromUrl(href)
          } catch (ex) {
            return
          }
          externals[href] = {
            name: $a.text(),
            filename: 'external-' + (Object.keys(externals).length + 1) + '.xhtml'
          }
          return externals[href].filename
        })
      })
      return stream.queueChapter(chapter)
    }).catch((err) => {
      console.error('Error while fetching chapter', chapterInfo, err.stack)
    })
  }).finally(() => {
    return concurrently(Object.keys(externals), maxConcurrency, (href, exterNum) => {
      return fic.getChapter(fetch, href).then((external) => {
        external.order = 9000 + exterNum
        external.name = 'External Reference #' + exterNum + ': ' + externals[href].name
        external.filename = externals[href].filename
        rewriteImages(fic.site, external, inlineImages(images))
        rewriteLinks(fic.site, external, linklocalChapters(fic, externals))
        return stream.queueChapter(external)
      }).catch((err) => {
        console.error('Warning, skipping external ' + href + ': ' + err)
        return stream.queueChapter({
          order: 9000 + exterNum,
          name: 'External Reference #' + exterNum + ': ' + externals[href].name,
          filename: externals[href].filename,
          content: '
External link to ' + href + '

' + err.stack + '
'
        })
      })
    })
  }).finally(() => {
    return concurrently(Object.keys(images), maxConcurrency, (src, imageNum) => {
      return fetch(src).spread((meta, imageData) => {
        return stream.queueChapter({
          image: true,
          filename: images[src].filename,
          content: imageData
        })
      })
    })
  }).finally(() => {
    return stream.queueChapter(null)
  }).catch(err => {
    console.error('Error in get fic ' + err)
  })
  return stream
}
<commit_msg>Support svg<commit_after>'use strict'
module.exports = getFic
var Bluebird = require('bluebird')
var Site = require('./site.js')
var cheerio = require('cheerio')
var chapterFilename = require('./chapter-filename.js')
var Readable = require('readable-stream').Readable
var inherits = require('util').inherits
var FicStream = require('./fic-stream.js')

function concurrently (_todo, concurrency, forEach) {
  var todo = Object.assign([], _todo)
  var run = 0
  var active = 0
  var aborted = false
  return new Bluebird((resolve, reject) => {
    function runNext () {
      if (aborted) return
      if (active === 0 && todo.length === 0) return resolve()
      while (active < concurrency && todo.length) {
        ++active
        forEach(todo.shift(), run++).then(() => {
          --active
          runNext()
          return null
        }).catch(err => {
          aborted = true
          reject(err)
        })
      }
    }
    runNext()
  })
}

function rewriteLinks (fic, chapter, handleLink) {
  var $ = cheerio.load(chapter.content)
  $('a').each((ii, a) => {
    var $a = $(a)
    var startAs = $a.attr('href')
    if (!startAs) {
      $a.remove()
      return
    }
    var href = fic.normalizeLink(startAs, chapter.base)
    var newHref = handleLink(href, $a)
    $a.attr('href', newHref || href)
  })
  chapter.content = $.html()
}

function rewriteImages (fic, chapter, handleImage) {
  var $ = cheerio.load(chapter.content)
  $('img').each((ii, img) => {
    var $img = $(img)
    var startAs = $img.attr('src')
    if (!startAs) return
    var src = fic.normalizeLink(startAs, chapter.base)
    var newsrc = handleImage(src, $img)
    $img.attr('src', newsrc || src)
  })
  chapter.content = $.html()
}

function findChapter (href, fic) {
  var matching = fic.chapters.filter(index => fic.normalizeLink(index.link) === fic.normalizeLink(href))
  return matching && matching[0]
}

function inlineImages (images) {
  return (src, $img) => {
    if (/clear[.]png$/.test(src)) return
    if (!images[src]) {
      var ext = src.match(/([.](?:jpe?g|gif|png|svg))/)
      ext = ext && ext[1]
      if (ext === '.jpeg') ext = '.jpg'
      images[src] = {
        filename: 'image-' + (Object.keys(images).length + 1) + (ext || '.guess.jpg')
      }
    }
    return images[src].filename
  }
}

function linklocalChapters (fic, externals) {
  return (href, $a, orElse) => {
    if (!orElse) orElse = () => { }
    if ($a.text() === '↑') {
      $a.remove()
      return
    }
    var linkedChapter = findChapter(href, fic)
    if (linkedChapter) {
      return chapterFilename(linkedChapter)
    } else if (externals[href]) {
      return externals[href].filename
    } else {
      return orElse(href) || href
    }
  }
}

function getFic (fetch, fic, maxConcurrency) {
  if (!maxConcurrency) maxConcurrency = 4
  var stream = new FicStream({highWaterMark: maxConcurrency * 2})
  var externals = {}
  var images = {}
  var chapters = fic.chapters

  concurrently(chapters, maxConcurrency, (chapterInfo) => {
    return fic.getChapter(fetch, chapterInfo.link).then((chapter) => {
      chapter.order = chapterInfo.order
      chapter.name = chapterInfo.name
      rewriteImages(fic, chapter, inlineImages(images))
      rewriteLinks(fic, chapter, (href, $a) => {
        return linklocalChapters(fic, externals)(href, $a, (href) => {
          if (!chapterInfo.externals) return
          try {
            var site = Site.fromUrl(href)
          } catch (ex) {
            return
          }
          externals[href] = {
            name: $a.text(),
            filename: 'external-' + (Object.keys(externals).length + 1) + '.xhtml'
          }
          return externals[href].filename
        })
      })
      return stream.queueChapter(chapter)
    }).catch((err) => {
      console.error('Error while fetching chapter', chapterInfo, err.stack)
    })
  }).finally(() => {
    return concurrently(Object.keys(externals), maxConcurrency, (href, exterNum) => {
      return fic.getChapter(fetch, href).then((external) => {
        external.order = 9000 + exterNum
        external.name = 'External Reference #' + exterNum + ': ' + externals[href].name
        external.filename = externals[href].filename
        rewriteImages(fic.site, external, inlineImages(images))
        rewriteLinks(fic.site, external, linklocalChapters(fic, externals))
        return stream.queueChapter(external)
      }).catch((err) => {
        console.error('Warning, skipping external ' + href + ': ' + err)
        return stream.queueChapter({
          order: 9000 + exterNum,
          name: 'External Reference #' + exterNum + ': ' + externals[href].name,
          filename: externals[href].filename,
          content: '
External link to ' + href + '

' + err.stack + '
'
        })
      })
    })
  }).finally(() => {
    return concurrently(Object.keys(images), maxConcurrency, (src, imageNum) => {
      return fetch(src).spread((meta, imageData) => {
        return stream.queueChapter({
          image: true,
          filename: images[src].filename,
          content: imageData
        })
      })
    })
  }).finally(() => {
    return stream.queueChapter(null)
  }).catch(err => {
    console.error('Error in get fic ' + err)
  })
  return stream
}
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 */
var _      = require('lodash');
var findup = require('findup-sync');
var fs     = require('fs');
var nomnom = require('nomnom');
var path   = require('path');

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

var HOME_DIR    = path.resolve(process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE);
var CONFIG_NAME = 'wct.conf.js';

// The full set of options, as a reference.
function defaults() {
  return {
    // The test suites that should be run.
    suites:      ['test/'],
    // Output stream to write log messages to.
    output:      process.stdout,
    // Whether the output stream should be treated as a TTY (and be given more
    // complex output formatting). Defaults to `output.isTTY`.
    ttyOutput:   undefined,
    // Spew all sorts of debugging messages.
    verbose:     false,
    // Display test results in expanded form. Verbose implies expanded.
    expanded:    false,
    // The on-disk path where tests & static files should be served from. Paths
    // (such as `suites`) are evaluated relative to this.
    //
    // By default, this is set to the directory above the current directory (so
    // that element repos can easily be tested with their dependencies).
    root:        undefined,
    // Idle timeout for tests.
    testTimeout: 90 * 1000,
    // Whether the browser should be closed after the tests run.
    persistent:  false,
    // Additional .js files to include in *generated* test indexes.
    extraScripts: [],
    // Webdriver capabilities objects for each browser that should be run.
    //
    // Capabilities can also contain a `url` value which is either a string URL
    // for the webdriver endpoint, or {hostname:, port:, user:, pwd:}.
    //
    // Most of the time you will want to rely on the WCT browser plugins to fill
    // this in for you (e.g. via `--local`, `--sauce`, etc).
    activeBrowsers: [],
    // Default capabilities to use when constructing webdriver connections (for
    // each browser specified in `activeBrowsers`). A handy place to hang common
    // configuration.
    //
    // TODO(nevir): Make sure this still works!
    //
    // Selenium: https://code.google.com/p/selenium/wiki/DesiredCapabilities
    // Sauce:    https://docs.saucelabs.com/reference/test-configuration/
    browserOptions: {},
    //
    plugins: ['local', 'sauce'],
  };
}

/** nomnom configuration for command line arguments.
 *
 * This might feel like duplication with `defaults()`, and out of place (why not
 * in `cli.js`?). But, not every option matches a configurable value, and it is
 * best to keep the configuration for these together to help keep them in sync.
 */
var ARG_CONFIG = {
  persistent: {
    help:      'Keep browsers active (refresh to rerun tests).',
    abbr:      'p',
    flag:      true,
  },
  root: {
    help:      'The root directory to serve tests from.',
    transform: path.resolve,
  },
  plugins: {
    help:      'Plugins that should be loaded.',
    metavar:   'NAME',
    full:      'plugin',
    list:       true,
  },
  expanded: {
    help:      'Log a status line for each test run.',
    flag:      true,
  },
  verbose: {
    help:      'Log all the things.',
    flag:      true,
  },
  simpleOutput: {
    help:      'Avoid fancy terminal output.',
    flag:      true,
  },

  // Deprecated

  browsers: {
    abbr:   'b',
    hidden: true,
    list:   true,
  },
  // TODO(nevir): Make work!
  remote: {
    abbr:   'r',
    hidden: true,
    flag:   true,
  }
};

// Values that should be extracted when pre-parsing args.
var PREPARSE_ARGS = ['plugins', 'simpleOutput'];

/**
 * Discovers appropriate config files (global, and for the project), merging
 * them, and returning them.
 *
 * @return {!Object} The merged configuration.
 */
function fromDisk() {
  var globalFile  = path.join(HOME_DIR, CONFIG_NAME);
  var projectFile = findup(CONFIG_NAME, {nocase: true});
  // Load a shared config from the user's home dir, if they have one, and then
  // try the project-specific path (starting at the current working directory).
  var paths   = _.unique([globalFile, projectFile]);
  var configs = _.filter(paths, fs.existsSync).map(require);
  var options = merge.apply(null, configs);

  if (!options.root && projectFile && projectFile !== globalFile) {
    process.chdir(path.dirname(projectFile));
  }

  return options;
}

/**
 * Runs a simplified options parse over the command line arguments, extracting
 * any values that are necessary for a full parse.
 *
 * At the moment, the only values extracted are `--plugin` and `--simpleOutput`.
 *
 * @param {!Array<string>} args
 * @return {!Object}
 */
function preparseArgs(args) {
  var parser = nomnom();
  parser.options(ARG_CONFIG);
  parser.printer(function() {});  // No-op output & errors.
  var options = parser.parse(args);

  return _.pick(options, PREPARSE_ARGS);
}

/**
 * Runs a complete options parse over the args, respecting plugin options.
 *
 * @param {!Context} context The context, containing plugin state and any base
 *     options to merge into.
 * @param {!Array<string>} args The args to parse.
 * @param {function(*)} done
 */
function parseArgs(context, args, done) {
  var parser = nomnom();
  parser.options(ARG_CONFIG);

  context.plugins(function(error, plugins) {
    if (error) return done(error);

    plugins.forEach(_configurePluginOptions.bind(null, parser));
    var options = _expandOptionPaths(normalize(parser.parse(args)));
    if (options._ && options._.length > 0) {
      options.suites = options._;
    }

    context.options = merge(context.options, options);
    done();
  });
}

function _configurePluginOptions(parser, plugin) {
  if (!plugin.cliConfig || plugin.cliConfig.length === 0) return;

  // Group options per plugin. It'd be nice to also have a header, but that ends
  // up shifting all the options over.
  parser.option('plugins.' + plugin.name + '.', {string: ' '});

  _.each(plugin.cliConfig, function(config, key) {
    // Make sure that we don't expose the name prefixes.
    if (!config.full) {
      config.full = key;
    }
    parser.option('plugins.' + plugin.name + '.' + key, config);
  });
}

function _expandOptionPaths(options) {
  var result = {};
  _.each(options, function(value, key) {
    var target = result;
    var parts  = key.split('.');
    for (var i = 0; i < parts.length - 1; i++) {
      target = target[parts[i]] = target[parts[i]] || {};
    }
    target[_.last(parts)] = value;
  });
  return result;
}

/**
 * @param {!Object...} configs Configuration objects to merge.
 * @return {!Object} The merged configuration, where configuration objects
 *     specified later in the arguments list are given precedence.
 */
function merge() {
  var result  = {};
  var configs = Array.prototype.map.call(arguments, normalize);
  return _.merge.apply(_, [result].concat(configs));
}

/**
 * @param {!Object} config Configuration object to normalize.
 * @return {!Object} `config`.
 */
function normalize(config) {
  if (_.isArray(config.plugins)) {
    var pluginConfigs = {};
    for (var i = 0, name; name = config.plugins[i]; i++) {
      pluginConfigs[name] = {};
    }
    config.plugins = pluginConfigs;
  }

  return config;
}

/**
 * Expands values within the configuration based on the current environment.
 *
 * @param {!Context} context The context for the current run.
 * @param {function(*)} done
 */
function expand(context, done) {
  var options = context.options;
  var root    = context.options.root || process.cwd();

  expandDeprecated(context, function(error) {
    if (error) return done(error);

    paths.expand(root, options.suites, function(error, suites) {
      if (error) return done(error);

      options.suites = suites;
      // Serve from the parent directory so that we can reference element deps.
      if (!options.root) {
        _serveFromParent(root, options);
      }

      done();
    });
  });
}

/**
 * Sets options.root to the parent directory of `baseDir`, and adjusts all
 * suites relative to it.
 *
 * @param {string} baseDir
 * @param {!Object} options
 */
function _serveFromParent(baseDir, options) {
  options.root = path.dirname(baseDir);

  var basename = path.basename(baseDir);
  options.suites = _.map(options.suites || [], function(file) {
    return path.join(basename, file);
  });
}

/**
 * Expands any options that have been deprecated, and warns about it.
 *
 * @param {!Context} context The context for the current run.
 */
function expandDeprecated(context, done) {
  var options = context.options;
  // We collect configuration fragments to be merged into the options object.
  var fragments = [];

  var browsers = _.isArray(options.browsers) ? options.browsers : [options.browsers];
  browsers = _.compact(browsers);
  if (browsers.length > 0) {
    context.emit('log:warn', 'The --browsers flag/option is deprecated. Please use --local and --sauce instead.');
    var fragment = {plugins: {sauce: {}, local: {}}};
    fragments.push(fragment);

    for (var i = 0, browser; browser = browsers[i]; i++) {
      var plugin = browser.indexOf('/') !== -1 ? 'sauce' : 'local';
      fragment.plugins[plugin].browsers = fragment.plugins[plugin].browsers || [];
      fragment.plugins[plugin].browsers.push(browser);
    }

    delete options.browsers;
  }

  if (options.sauce) {
    context.emit('log:warn', 'The sauce configuration key is deprecated. Please use plugins.sauce instead.');
    fragments.push({
      plugins: {sauce: options.sauce},
    });
    delete options.sauce;
  }

  if (options.remote) {
    context.emit('log:warn', 'The --remote flag is deprecated. Please use --sauce default instead.');
    fragments.push({
      plugins: {sauce: {browsers: ['default']}},
    });
    delete options.remote;
  }

  if (fragments.length > 0) {
    // We are careful to modify context.options in place.
    _.merge(context.options, merge.apply(null, fragments));
  }

  done();
}

/**
 * @param {!Object} options The configuration to validate.
 * @param {function(*)} Callback indicating whether the configuration is valid.
 */
function validate(options, done) {
  if (options.webRunner) {
    return done('webRunner is no longer a supported configuration option. Please list the files you wish to test as arguments, or as `suites` in a configuration object.');
  }
  if (options.component) {
    return done('component is no longer a supported configuration option. Please list the files you wish to test as arguments, or as `suites` in a configuration object.');
  }

  if (options.activeBrowsers.length === 0) {
    return done('No browsers configured to run');
  }
  if (options.suites.length === 0) {
    return done('No test suites were found matching your configuration');
  }

  done(null);
}

module.exports = {
  defaults:     defaults,
  fromDisk:     fromDisk,
  preparseArgs: preparseArgs,
  parseArgs:    parseArgs,
  merge:        merge,
  normalize:    normalize,
  expand:       expand,
  validate:     validate,
};
<commit_msg>One TODO gone<commit_after>/**
 * @license
 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 */
var _      = require('lodash');
var findup = require('findup-sync');
var fs     = require('fs');
var nomnom = require('nomnom');
var path   = require('path');

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

var HOME_DIR    = path.resolve(process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE);
var CONFIG_NAME = 'wct.conf.js';

// The full set of options, as a reference.
function defaults() {
  return {
    // The test suites that should be run.
    suites:      ['test/'],
    // Output stream to write log messages to.
    output:      process.stdout,
    // Whether the output stream should be treated as a TTY (and be given more
    // complex output formatting). Defaults to `output.isTTY`.
    ttyOutput:   undefined,
    // Spew all sorts of debugging messages.
    verbose:     false,
    // Display test results in expanded form. Verbose implies expanded.
    expanded:    false,
    // The on-disk path where tests & static files should be served from. Paths
    // (such as `suites`) are evaluated relative to this.
    //
    // By default, this is set to the directory above the current directory (so
    // that element repos can easily be tested with their dependencies).
    root:        undefined,
    // Idle timeout for tests.
    testTimeout: 90 * 1000,
    // Whether the browser should be closed after the tests run.
    persistent:  false,
    // Additional .js files to include in *generated* test indexes.
    extraScripts: [],
    // Webdriver capabilities objects for each browser that should be run.
    //
    // Capabilities can also contain a `url` value which is either a string URL
    // for the webdriver endpoint, or {hostname:, port:, user:, pwd:}.
    //
    // Most of the time you will want to rely on the WCT browser plugins to fill
    // this in for you (e.g. via `--local`, `--sauce`, etc).
    activeBrowsers: [],
    // Default capabilities to use when constructing webdriver connections (for
    // each browser specified in `activeBrowsers`). A handy place to hang common
    // configuration.
    //
    // TODO(nevir): Make sure this still works!
    //
    // Selenium: https://code.google.com/p/selenium/wiki/DesiredCapabilities
    // Sauce:    https://docs.saucelabs.com/reference/test-configuration/
    browserOptions: {},
    //
    plugins: ['local', 'sauce'],
  };
}

/** nomnom configuration for command line arguments.
 *
 * This might feel like duplication with `defaults()`, and out of place (why not
 * in `cli.js`?). But, not every option matches a configurable value, and it is
 * best to keep the configuration for these together to help keep them in sync.
 */
var ARG_CONFIG = {
  persistent: {
    help:      'Keep browsers active (refresh to rerun tests).',
    abbr:      'p',
    flag:      true,
  },
  root: {
    help:      'The root directory to serve tests from.',
    transform: path.resolve,
  },
  plugins: {
    help:      'Plugins that should be loaded.',
    metavar:   'NAME',
    full:      'plugin',
    list:       true,
  },
  expanded: {
    help:      'Log a status line for each test run.',
    flag:      true,
  },
  verbose: {
    help:      'Log all the things.',
    flag:      true,
  },
  simpleOutput: {
    help:      'Avoid fancy terminal output.',
    flag:      true,
  },

  // Deprecated

  browsers: {
    abbr:   'b',
    hidden: true,
    list:   true,
  },
  remote: {
    abbr:   'r',
    hidden: true,
    flag:   true,
  }
};

// Values that should be extracted when pre-parsing args.
var PREPARSE_ARGS = ['plugins', 'simpleOutput'];

/**
 * Discovers appropriate config files (global, and for the project), merging
 * them, and returning them.
 *
 * @return {!Object} The merged configuration.
 */
function fromDisk() {
  var globalFile  = path.join(HOME_DIR, CONFIG_NAME);
  var projectFile = findup(CONFIG_NAME, {nocase: true});
  // Load a shared config from the user's home dir, if they have one, and then
  // try the project-specific path (starting at the current working directory).
  var paths   = _.unique([globalFile, projectFile]);
  var configs = _.filter(paths, fs.existsSync).map(require);
  var options = merge.apply(null, configs);

  if (!options.root && projectFile && projectFile !== globalFile) {
    process.chdir(path.dirname(projectFile));
  }

  return options;
}

/**
 * Runs a simplified options parse over the command line arguments, extracting
 * any values that are necessary for a full parse.
 *
 * At the moment, the only values extracted are `--plugin` and `--simpleOutput`.
 *
 * @param {!Array<string>} args
 * @return {!Object}
 */
function preparseArgs(args) {
  var parser = nomnom();
  parser.options(ARG_CONFIG);
  parser.printer(function() {});  // No-op output & errors.
  var options = parser.parse(args);

  return _.pick(options, PREPARSE_ARGS);
}

/**
 * Runs a complete options parse over the args, respecting plugin options.
 *
 * @param {!Context} context The context, containing plugin state and any base
 *     options to merge into.
 * @param {!Array<string>} args The args to parse.
 * @param {function(*)} done
 */
function parseArgs(context, args, done) {
  var parser = nomnom();
  parser.options(ARG_CONFIG);

  context.plugins(function(error, plugins) {
    if (error) return done(error);

    plugins.forEach(_configurePluginOptions.bind(null, parser));
    var options = _expandOptionPaths(normalize(parser.parse(args)));
    if (options._ && options._.length > 0) {
      options.suites = options._;
    }

    context.options = merge(context.options, options);
    done();
  });
}

function _configurePluginOptions(parser, plugin) {
  if (!plugin.cliConfig || plugin.cliConfig.length === 0) return;

  // Group options per plugin. It'd be nice to also have a header, but that ends
  // up shifting all the options over.
  parser.option('plugins.' + plugin.name + '.', {string: ' '});

  _.each(plugin.cliConfig, function(config, key) {
    // Make sure that we don't expose the name prefixes.
    if (!config.full) {
      config.full = key;
    }
    parser.option('plugins.' + plugin.name + '.' + key, config);
  });
}

function _expandOptionPaths(options) {
  var result = {};
  _.each(options, function(value, key) {
    var target = result;
    var parts  = key.split('.');
    for (var i = 0; i < parts.length - 1; i++) {
      target = target[parts[i]] = target[parts[i]] || {};
    }
    target[_.last(parts)] = value;
  });
  return result;
}

/**
 * @param {!Object...} configs Configuration objects to merge.
 * @return {!Object} The merged configuration, where configuration objects
 *     specified later in the arguments list are given precedence.
 */
function merge() {
  var result  = {};
  var configs = Array.prototype.map.call(arguments, normalize);
  return _.merge.apply(_, [result].concat(configs));
}

/**
 * @param {!Object} config Configuration object to normalize.
 * @return {!Object} `config`.
 */
function normalize(config) {
  if (_.isArray(config.plugins)) {
    var pluginConfigs = {};
    for (var i = 0, name; name = config.plugins[i]; i++) {
      pluginConfigs[name] = {};
    }
    config.plugins = pluginConfigs;
  }

  return config;
}

/**
 * Expands values within the configuration based on the current environment.
 *
 * @param {!Context} context The context for the current run.
 * @param {function(*)} done
 */
function expand(context, done) {
  var options = context.options;
  var root    = context.options.root || process.cwd();

  expandDeprecated(context, function(error) {
    if (error) return done(error);

    paths.expand(root, options.suites, function(error, suites) {
      if (error) return done(error);

      options.suites = suites;
      // Serve from the parent directory so that we can reference element deps.
      if (!options.root) {
        _serveFromParent(root, options);
      }

      done();
    });
  });
}

/**
 * Sets options.root to the parent directory of `baseDir`, and adjusts all
 * suites relative to it.
 *
 * @param {string} baseDir
 * @param {!Object} options
 */
function _serveFromParent(baseDir, options) {
  options.root = path.dirname(baseDir);

  var basename = path.basename(baseDir);
  options.suites = _.map(options.suites || [], function(file) {
    return path.join(basename, file);
  });
}

/**
 * Expands any options that have been deprecated, and warns about it.
 *
 * @param {!Context} context The context for the current run.
 */
function expandDeprecated(context, done) {
  var options = context.options;
  // We collect configuration fragments to be merged into the options object.
  var fragments = [];

  var browsers = _.isArray(options.browsers) ? options.browsers : [options.browsers];
  browsers = _.compact(browsers);
  if (browsers.length > 0) {
    context.emit('log:warn', 'The --browsers flag/option is deprecated. Please use --local and --sauce instead.');
    var fragment = {plugins: {sauce: {}, local: {}}};
    fragments.push(fragment);

    for (var i = 0, browser; browser = browsers[i]; i++) {
      var plugin = browser.indexOf('/') !== -1 ? 'sauce' : 'local';
      fragment.plugins[plugin].browsers = fragment.plugins[plugin].browsers || [];
      fragment.plugins[plugin].browsers.push(browser);
    }

    delete options.browsers;
  }

  if (options.sauce) {
    context.emit('log:warn', 'The sauce configuration key is deprecated. Please use plugins.sauce instead.');
    fragments.push({
      plugins: {sauce: options.sauce},
    });
    delete options.sauce;
  }

  if (options.remote) {
    context.emit('log:warn', 'The --remote flag is deprecated. Please use --sauce default instead.');
    fragments.push({
      plugins: {sauce: {browsers: ['default']}},
    });
    delete options.remote;
  }

  if (fragments.length > 0) {
    // We are careful to modify context.options in place.
    _.merge(context.options, merge.apply(null, fragments));
  }

  done();
}

/**
 * @param {!Object} options The configuration to validate.
 * @param {function(*)} Callback indicating whether the configuration is valid.
 */
function validate(options, done) {
  if (options.webRunner) {
    return done('webRunner is no longer a supported configuration option. Please list the files you wish to test as arguments, or as `suites` in a configuration object.');
  }
  if (options.component) {
    return done('component is no longer a supported configuration option. Please list the files you wish to test as arguments, or as `suites` in a configuration object.');
  }

  if (options.activeBrowsers.length === 0) {
    return done('No browsers configured to run');
  }
  if (options.suites.length === 0) {
    return done('No test suites were found matching your configuration');
  }

  done(null);
}

module.exports = {
  defaults:     defaults,
  fromDisk:     fromDisk,
  preparseArgs: preparseArgs,
  parseArgs:    parseArgs,
  merge:        merge,
  normalize:    normalize,
  expand:       expand,
  validate:     validate,
};
<|endoftext|>


<commit_before>/* global describe, after, before */
'use strict';

var async = require('async');
var fs = require('fs-extra');
var nock = require('nock');
var Updater = require('landsat-meta-updater');
var Server = require('../app/services/server.js');
var client = require('../app/services/elasticsearch.js');
var shared = require('./shared');

describe('Elasticsearch tests', function () {
  this.timeout(7000);
  var testIndex = 'test_main';
  var testType = '8';
  var downloadDir = __dirname + '/download';
  var self = this;
  var port = 2000

  before(function (done) {
    process.env['ES_INDEX'] = testIndex;
    process.env['DB_TYPE'] = 'landsat';
    process.env['ES_HOST'] = 'localhost:9200';

    // Add records to elasticsearch
    var csv = fs.readFileSync('./test/test_data.csv', {encoding: 'utf8'});
    nock('http://landsat.usgs.gov')
      .get('/metadata_service/bulk_metadata_files/LANDSAT_8.csv')
      .reply(200, csv);

    var u = new Updater(testIndex, testType, 5, downloadDir);

    async.waterfall([
      // Add records to ES
      function (callback) {
        u.updateEs(callback);
      },

      // Start server
      function (msg, callback) {
        self.server = new Server(port);
        self.server.start(callback);
      }
    ], function (err) {
      if (err) console.log(err);

      // Wait for 3000 ms
      setTimeout(function () {
        done();
      }, 3000);
    });
  });

  // Run tests
  shared(port);

  after(function (done) {
    client.indices.delete({index: testIndex}).then(function () {
      fs.removeSync(downloadDir);
      self.server.hapi.stop(done);
    }).catch(function (err) {
      if (err) console.log(err);
    });
  });
});
<commit_msg>use fs<commit_after>/* global describe, after, before */
'use strict';

var async = require('async');
var fs = require('fs');
var nock = require('nock');
var Updater = require('landsat-meta-updater');
var Server = require('../app/services/server.js');
var client = require('../app/services/elasticsearch.js');
var shared = require('./shared');

describe('Elasticsearch tests', function () {
  this.timeout(7000);
  var testIndex = 'test_main';
  var testType = '8';
  var downloadDir = __dirname + '/download';
  var self = this;
  var port = 2000

  before(function (done) {
    process.env['ES_INDEX'] = testIndex;
    process.env['DB_TYPE'] = 'landsat';
    process.env['ES_HOST'] = 'localhost:9200';

    // Add records to elasticsearch
    var csv = fs.readFileSync(__dirname + '/test_data.csv', {encoding: 'utf8'});
    nock('http://landsat.usgs.gov')
      .get('/metadata_service/bulk_metadata_files/LANDSAT_8.csv')
      .reply(200, csv);

    var u = new Updater(testIndex, testType, 5, downloadDir);

    async.waterfall([
      // Add records to ES
      function (callback) {
        u.updateEs(callback);
      },

      // Start server
      function (msg, callback) {
        self.server = new Server(port);
        self.server.start(callback);
      }
    ], function (err) {
      if (err) console.log(err);

      // Wait for 3000 ms
      setTimeout(function () {
        done();
      }, 3000);
    });
  });

  // Run tests
  shared(port);

  after(function (done) {
    client.indices.delete({index: testIndex}).then(function () {
      fs.unlinkSync(downloadDir + '/landsat.csv');
      fs.rmdirSync(downloadDir);
      self.server.hapi.stop(done);
    }).catch(function (err) {
      if (err) console.log(err);
    });
  });
});
<|endoftext|>


<commit_before>javascript:
(function() {

	var link = "";
	if (mw.config.get("wgDiffNewId")) {
		if ($(".diff-multi").length > 0) {
			link = "Special:Diff/" + mw.config.get("wgDiffOldId") + "/" + mw.config.get("wgDiffNewId");
		} else {
			link = "Special:Diff/" + mw.config.get("wgDiffNewId");
		}
	} else if (mw.config.get("wgRevisionId")) {
		link = "Special:PermaLink/" + mw.config.get("wgRevisionId");
	} else {
		mw.notify("Cannot get link");
		return;
	}

	var hash = decodeURIComponent(location.hash);
	hash = hash.replace(/{/g, '{');
	hash = hash.replace(/}/g, '}');
	link += hash;

	prompt("wikitext", "[[" + link + "]]");

})();
<commit_msg>Ask whether to use short diff link<commit_after>javascript:
(function() {

	var link = "";
	if (mw.config.get("wgDiffNewId")) {
		if (!$(".diff-multi").length && confirm('Short version?')) {
			link = "Special:Diff/" + mw.config.get("wgDiffNewId");
		} else {
			link = "Special:Diff/" + mw.config.get("wgDiffOldId") + "/" + mw.config.get("wgDiffNewId");
		}
	} else if (mw.config.get("wgRevisionId")) {
		link = "Special:PermaLink/" + mw.config.get("wgRevisionId");
	} else {
		mw.notify("Cannot get link");
		return;
	}

	var hash = decodeURIComponent(location.hash);
	hash = hash.replace(/{/g, '{');
	hash = hash.replace(/}/g, '}');
	link += hash;

	prompt("wikitext", "[[" + link + "]]");

})();
<|endoftext|>


<commit_before>'use strict'

// //////////////////////////////////////////////////////////////////////////
// actionhero framework in node.js
// http://www.actionherojs.com
// https://github.com/evantahler/actionhero

const path = require('path')
const async = require('async')

// HELPERS ///

const fatalError = function (api, errors, type) {
  if (errors && !(errors instanceof Array)) { errors = [errors] }
  if (errors) {
    if (api.log) {
      api.log(['Error with initializer step: %s', type], 'emerg')
      errors.forEach((error) => { api.log(error.stack, 'emerg') })
    } else {
      console.error('Error with initializer step: ' + type)
      errors.forEach((error) => { console.error(error.stack) })
    }
    api.commands.stop.call(api, () => {
      process.exit(1)
    })
  }
}

const sortNumber = function (a, b) {
  return a - b
}

let startCount = 0

const flattenOrderedInitialzer = function (collection) {
  let output = []
  let keys = []
  for (let key in collection) {
    keys.push(parseInt(key))
  }
  keys.sort(sortNumber)
  keys.forEach((key) => {
    collection[key].forEach((d) => {
      output.push(d)
    })
  })

  return output
}

// ACTIONHERO //

const actionhero = function () {
  this.initializers = {}
  this.api = {
    running: false,
    initialized: false,
    shuttingDown: false
  }
}

actionhero.prototype.initialize = function (params, callback) {
  this.api.commands = {
    initialize: (params, callback) => { this.initialize(params, callback) },
    start: (params, callback) => { this.start(params, callback) },
    stop: (callback) => { this.stop(callback) },
    restart: (callback) => { this.restart(callback) }
  }

  this.api.projectRoot = process.cwd()

  if (process.env.project_root) {
    this.api.projectRoot = process.env.project_root
  } else if (process.env.projectRoot) {
    this.api.projectRoot = process.env.projectRoot
  } else if (process.env.PROJECT_ROOT) {
    this.api.projectRoot = process.env.PROJECT_ROOT
  }

  if (!callback && typeof params === 'function') {
    callback = params; params = {}
  }
  if (params === null) { params = {} }
  this.startingParams = params
  this.api._startingParams = this.startingParams

  this.api.initializerDefaults = {
    load: 1000,
    start: 1000,
    stop: 1000
  }

  let loadInitializerRankings = {}
  let startInitializerRankings = {}
  let stopInitializerRankings = {}

  this.configInitializers = []
  this.loadInitializers = []
  this.startInitializers = []
  this.stopInitializers = [];

  // we need to load the config first
  [
    path.resolve(__dirname, 'initializers', 'utils.js'),
    path.resolve(__dirname, 'initializers', 'config.js')
  ].forEach((file) => {
    let filename = file.replace(/^.*[\\/]/, '')
    let initializer = filename.split('.')[0]
    delete require.cache[require.resolve(file)]
    this.initializers[initializer] = require(file)
    this.configInitializers.push((next) => {
      this.initializers[initializer].initialize(this.api, next)
    })
  })

  this.configInitializers.push(() => {
    let customInitializers = []
    let ignoredInitializers = []
    this.api.config.general.paths.initializer.forEach((startPath) => {
      customInitializers = customInitializers.concat(this.api.utils.recursiveDirectoryGlob(startPath))
    })
    // load all other initializers
    this.api.utils.arrayUniqueify(
      this.api.utils.recursiveDirectoryGlob(path.join(__dirname, 'initializers'))
      .sort()
      .concat(
        customInitializers
        .sort()
      )
    ).forEach((f) => {
      let file = path.normalize(f)
      let initializer = path.basename(f).split('.')[0]
      let fileParts = file.split('.')
      let ext = fileParts[(fileParts.length - 1)]
      if (ext === 'js') {
        // check if initializer already exists (exclude utils and config)
        if (this.initializers[initializer] &&
           file !== path.resolve(__dirname, 'initializers', 'utils.js') &&
           file !== path.resolve(__dirname, 'initializers', 'config.js')) {
          ignoredInitializers.push(file)
        } else {
          delete require.cache[require.resolve(file)]
          this.initializers[initializer] = require(file)
        }

        const loadFunction = (next) => {
          this.api.watchFileAndAct(file, () => {
            this.api.log(['*** Rebooting due to initializer change (%s) ***', file], 'info')
            this.api.commands.restart()
          })

          if (typeof this.initializers[initializer].initialize === 'function') {
            if (typeof this.api.log === 'function') { this.api.log(['Loading initializer: %s', initializer], 'debug', file) }
            this.initializers[initializer].initialize(this.api, (error) => {
              try { this.api.log(['Loaded initializer: %s', initializer], 'debug', file) } catch (e) { }
              next(error)
            })
          } else {
            next()
          }
        }

        const startFunction = (next) => {
          if (typeof this.initializers[initializer].start === 'function') {
            if (typeof this.api.log === 'function') { this.api.log(['Starting initializer: %s', initializer], 'debug', file) }
            this.initializers[initializer].start(this.api, (error) => {
              this.api.log(['Started initializer: %s', initializer], 'debug', file)
              next(error)
            })
          } else {
            next()
          }
        }

        const stopFunction = (next) => {
          if (typeof this.initializers[initializer].stop === 'function') {
            if (typeof this.api.log === 'function') { this.api.log(['Stopping initializer: %s', initializer], 'debug', file) }
            this.initializers[initializer].stop(this.api, (error) => {
              this.api.log(['Stopped initializer: %s', initializer], 'debug', file)
              next(error)
            })
          } else {
            next()
          }
        }

        if (this.initializers[initializer].loadPriority === undefined) {
          this.initializers[initializer].loadPriority = this.api.initializerDefaults.load
        }
        if (this.initializers[initializer].startPriority === undefined) {
          this.initializers[initializer].startPriority = this.api.initializerDefaults.start
        }
        if (this.initializers[initializer].stopPriority === undefined) {
          this.initializers[initializer].stopPriority = this.api.initializerDefaults.stop
        }

        if (loadInitializerRankings[this.initializers[initializer].loadPriority] === undefined) {
          loadInitializerRankings[this.initializers[initializer].loadPriority] = []
        }
        if (startInitializerRankings[this.initializers[initializer].startPriority] === undefined) {
          startInitializerRankings[this.initializers[initializer].startPriority] = []
        }
        if (stopInitializerRankings[this.initializers[initializer].stopPriority] === undefined) {
          stopInitializerRankings[this.initializers[initializer].stopPriority] = []
        }

        if (this.initializers[initializer].loadPriority > 0) {
          loadInitializerRankings[this.initializers[initializer].loadPriority].push(loadFunction)
        }

        if (this.initializers[initializer].startPriority > 0) {
          startInitializerRankings[this.initializers[initializer].startPriority].push(startFunction)
        }

        if (this.initializers[initializer].stopPriority > 0) {
          stopInitializerRankings[this.initializers[initializer].stopPriority].push(stopFunction)
        }
      }
    })

    // flatten all the ordered initializer methods
    this.loadInitializers = flattenOrderedInitialzer(loadInitializerRankings)
    this.startInitializers = flattenOrderedInitialzer(startInitializerRankings)
    this.stopInitializers = flattenOrderedInitialzer(stopInitializerRankings)

    this.loadInitializers.push(() => {
      process.nextTick(() => {
        this.api.initialized = true

        if (ignoredInitializers.length > 0) {
          ignoredInitializers.forEach(initializer => this.api.log(['Ignored Initializer %s because the file already exists!', initializer], 'error'))
          ignoredInitializers = []
        }
        callback(null, this.api)
      })
    })

    async.series(this.loadInitializers, (errors) => { fatalError(this.api, errors, 'initialize') })
  })

  async.series(this.configInitializers, (errors) => { fatalError(this.api, errors, 'config') })
}

actionhero.prototype.start = function (params, callback) {
  if (!callback && typeof params === 'function') {
    callback = params; params = {}
  }

  const _start = () => {
    this.api.running = true

    this.startInitializers.push(() => {
      this.api.bootTime = new Date().getTime()
      if (startCount === 0) {
        this.api.log(['*** ActionHero Started ***'], 'alert')
      } else {
        this.api.log(['*** ActionHero Restarted ***'], 'alert')
      }

      startCount++
      callback(null, this.api)
    })

    async.series(this.startInitializers, (errors) => { fatalError(this.api, errors, 'start') })
  }

  if (this.api.initialized === true) {
    _start()
  } else {
    this.initialize(params, () => {
      _start()
    })
  }
}

actionhero.prototype.stop = function (callback) {
  if (this.api.running === true) {
    this.api.shuttingDown = true
    this.api.running = false
    this.api.initialized = false

    this.api.log('Shutting down open servers and stopping task processing...', 'notice')

    this.stopInitializers.push(() => {
      this.api.unWatchAllFiles()
      this.api.pids.clearPidFile()
      this.api.log('*** ActionHero Stopped ***', 'alert')
      this.api.log('***', 'debug')
      delete this.api.shuttingDown
      process.nextTick(() => {
        if (typeof callback === 'function') { callback(null, this.api) }
      })
    })

    async.series(this.stopInitializers, (errors) => { fatalError(this.api, errors, 'stop') })
  } else if (this.api.shuttingDown === true) {
    // double sigterm; ignore it
  } else {
    if (this.api.log) { this.api.log('Cannot shut down actionhero, not running', 'error') }
    if (typeof callback === 'function') { callback(null, this.api) }
  }
}

actionhero.prototype.restart = function (callback) {
  if (this.api.running === true) {
    this.stop((error) => {
      if (error) { this.api.log(error, 'error') }
      this.start(this.startingParams, (error) => {
        if (error) { this.api.log(error, 'error') }
        if (typeof callback === 'function') { callback(null, this.api) }
      })
    })
  } else {
    this.start(this.startingParams, (error) => {
      if (error) { this.api.log(error, 'error') }
      if (typeof callback === 'function') { callback(null, this.api) }
    })
  }
}

module.exports = actionhero
<commit_msg>added fatal error<commit_after>'use strict'

// //////////////////////////////////////////////////////////////////////////
// actionhero framework in node.js
// http://www.actionherojs.com
// https://github.com/evantahler/actionhero

const path = require('path')
const async = require('async')

// HELPERS ///

const fatalError = function (api, errors, type) {
  if (errors && !(errors instanceof Array)) { errors = [errors] }
  if (errors) {
    if (api.log) {
      api.log(['Error with initializer step: %s', type], 'emerg')
      errors.forEach((error) => { api.log(error.stack, 'emerg') })
    } else {
      console.error('Error with initializer step: ' + type)
      errors.forEach((error) => { console.error(error.stack) })
    }
    api.commands.stop.call(api, () => {
      process.exit(1)
    })
  }
}

const sortNumber = function (a, b) {
  return a - b
}

let startCount = 0

const flattenOrderedInitialzer = function (collection) {
  let output = []
  let keys = []
  for (let key in collection) {
    keys.push(parseInt(key))
  }
  keys.sort(sortNumber)
  keys.forEach((key) => {
    collection[key].forEach((d) => {
      output.push(d)
    })
  })

  return output
}

// ACTIONHERO //

const actionhero = function () {
  this.initializers = {}
  this.api = {
    running: false,
    initialized: false,
    shuttingDown: false
  }
}

actionhero.prototype.initialize = function (params, callback) {
  this.api.commands = {
    initialize: (params, callback) => { this.initialize(params, callback) },
    start: (params, callback) => { this.start(params, callback) },
    stop: (callback) => { this.stop(callback) },
    restart: (callback) => { this.restart(callback) }
  }

  this.api.projectRoot = process.cwd()

  if (process.env.project_root) {
    this.api.projectRoot = process.env.project_root
  } else if (process.env.projectRoot) {
    this.api.projectRoot = process.env.projectRoot
  } else if (process.env.PROJECT_ROOT) {
    this.api.projectRoot = process.env.PROJECT_ROOT
  }

  if (!callback && typeof params === 'function') {
    callback = params; params = {}
  }
  if (params === null) { params = {} }
  this.startingParams = params
  this.api._startingParams = this.startingParams

  this.api.initializerDefaults = {
    load: 1000,
    start: 1000,
    stop: 1000
  }

  let loadInitializerRankings = {}
  let startInitializerRankings = {}
  let stopInitializerRankings = {}

  this.configInitializers = []
  this.loadInitializers = []
  this.startInitializers = []
  this.stopInitializers = [];

  // we need to load the config first
  [
    path.resolve(__dirname, 'initializers', 'utils.js'),
    path.resolve(__dirname, 'initializers', 'config.js')
  ].forEach((file) => {
    let filename = file.replace(/^.*[\\/]/, '')
    let initializer = filename.split('.')[0]
    delete require.cache[require.resolve(file)]
    this.initializers[initializer] = require(file)
    this.configInitializers.push((next) => {
      this.initializers[initializer].initialize(this.api, next)
    })
  })

  this.configInitializers.push(() => {
    let customInitializers = []
    let ignoredInitializers = []
    this.api.config.general.paths.initializer.forEach((startPath) => {
      customInitializers = customInitializers.concat(this.api.utils.recursiveDirectoryGlob(startPath))
    })
    // load all other initializers
    this.api.utils.arrayUniqueify(
      this.api.utils.recursiveDirectoryGlob(path.join(__dirname, 'initializers'))
      .sort()
      .concat(
        customInitializers
        .sort()
      )
    ).forEach((f) => {
      let file = path.normalize(f)
      let initializer = path.basename(f).split('.')[0]
      let fileParts = file.split('.')
      let ext = fileParts[(fileParts.length - 1)]
      if (ext === 'js') {
        // check if initializer already exists (exclude utils and config)
        if (this.initializers[initializer] &&
           file !== path.resolve(__dirname, 'initializers', 'utils.js') &&
           file !== path.resolve(__dirname, 'initializers', 'config.js')) {
          ignoredInitializers.push(file)
        } else {
          delete require.cache[require.resolve(file)]
          this.initializers[initializer] = require(file)
        }

        const loadFunction = (next) => {
          this.api.watchFileAndAct(file, () => {
            this.api.log(['*** Rebooting due to initializer change (%s) ***', file], 'info')
            this.api.commands.restart()
          })

          if (typeof this.initializers[initializer].initialize === 'function') {
            if (typeof this.api.log === 'function') { this.api.log(['Loading initializer: %s', initializer], 'debug', file) }
            this.initializers[initializer].initialize(this.api, (error) => {
              try { this.api.log(['Loaded initializer: %s', initializer], 'debug', file) } catch (e) { }
              next(error)
            })
          } else {
            next()
          }
        }

        const startFunction = (next) => {
          if (typeof this.initializers[initializer].start === 'function') {
            if (typeof this.api.log === 'function') { this.api.log(['Starting initializer: %s', initializer], 'debug', file) }
            this.initializers[initializer].start(this.api, (error) => {
              this.api.log(['Started initializer: %s', initializer], 'debug', file)
              next(error)
            })
          } else {
            next()
          }
        }

        const stopFunction = (next) => {
          if (typeof this.initializers[initializer].stop === 'function') {
            if (typeof this.api.log === 'function') { this.api.log(['Stopping initializer: %s', initializer], 'debug', file) }
            this.initializers[initializer].stop(this.api, (error) => {
              this.api.log(['Stopped initializer: %s', initializer], 'debug', file)
              next(error)
            })
          } else {
            next()
          }
        }

        if (this.initializers[initializer].loadPriority === undefined) {
          this.initializers[initializer].loadPriority = this.api.initializerDefaults.load
        }
        if (this.initializers[initializer].startPriority === undefined) {
          this.initializers[initializer].startPriority = this.api.initializerDefaults.start
        }
        if (this.initializers[initializer].stopPriority === undefined) {
          this.initializers[initializer].stopPriority = this.api.initializerDefaults.stop
        }

        if (loadInitializerRankings[this.initializers[initializer].loadPriority] === undefined) {
          loadInitializerRankings[this.initializers[initializer].loadPriority] = []
        }
        if (startInitializerRankings[this.initializers[initializer].startPriority] === undefined) {
          startInitializerRankings[this.initializers[initializer].startPriority] = []
        }
        if (stopInitializerRankings[this.initializers[initializer].stopPriority] === undefined) {
          stopInitializerRankings[this.initializers[initializer].stopPriority] = []
        }

        if (this.initializers[initializer].loadPriority > 0) {
          loadInitializerRankings[this.initializers[initializer].loadPriority].push(loadFunction)
        }

        if (this.initializers[initializer].startPriority > 0) {
          startInitializerRankings[this.initializers[initializer].startPriority].push(startFunction)
        }

        if (this.initializers[initializer].stopPriority > 0) {
          stopInitializerRankings[this.initializers[initializer].stopPriority].push(stopFunction)
        }
      }
    })

    // flatten all the ordered initializer methods
    this.loadInitializers = flattenOrderedInitialzer(loadInitializerRankings)
    this.startInitializers = flattenOrderedInitialzer(startInitializerRankings)
    this.stopInitializers = flattenOrderedInitialzer(stopInitializerRankings)

    this.loadInitializers.push(() => {
      process.nextTick(() => {
        this.api.initialized = true

        if (ignoredInitializers.length > 0) {
          ignoredInitializers.forEach(initializer => this.api.log(['Initializer %s already exists!', initializer], 'error'))
          this.api.commands.stop.call(this.api, () => {
            process.exit(1)
          })
        }
        callback(null, this.api)
      })
    })

    async.series(this.loadInitializers, (errors) => { fatalError(this.api, errors, 'initialize') })
  })

  async.series(this.configInitializers, (errors) => { fatalError(this.api, errors, 'config') })
}

actionhero.prototype.start = function (params, callback) {
  if (!callback && typeof params === 'function') {
    callback = params; params = {}
  }

  const _start = () => {
    this.api.running = true

    this.startInitializers.push(() => {
      this.api.bootTime = new Date().getTime()
      if (startCount === 0) {
        this.api.log(['*** ActionHero Started ***'], 'alert')
      } else {
        this.api.log(['*** ActionHero Restarted ***'], 'alert')
      }

      startCount++
      callback(null, this.api)
    })

    async.series(this.startInitializers, (errors) => { fatalError(this.api, errors, 'start') })
  }

  if (this.api.initialized === true) {
    _start()
  } else {
    this.initialize(params, () => {
      _start()
    })
  }
}

actionhero.prototype.stop = function (callback) {
  if (this.api.running === true) {
    this.api.shuttingDown = true
    this.api.running = false
    this.api.initialized = false

    this.api.log('Shutting down open servers and stopping task processing...', 'notice')

    this.stopInitializers.push(() => {
      this.api.unWatchAllFiles()
      this.api.pids.clearPidFile()
      this.api.log('*** ActionHero Stopped ***', 'alert')
      this.api.log('***', 'debug')
      delete this.api.shuttingDown
      process.nextTick(() => {
        if (typeof callback === 'function') { callback(null, this.api) }
      })
    })

    async.series(this.stopInitializers, (errors) => { fatalError(this.api, errors, 'stop') })
  } else if (this.api.shuttingDown === true) {
    // double sigterm; ignore it
  } else {
    if (this.api.log) { this.api.log('Cannot shut down actionhero, not running', 'error') }
    if (typeof callback === 'function') { callback(null, this.api) }
  }
}

actionhero.prototype.restart = function (callback) {
  if (this.api.running === true) {
    this.stop((error) => {
      if (error) { this.api.log(error, 'error') }
      this.start(this.startingParams, (error) => {
        if (error) { this.api.log(error, 'error') }
        if (typeof callback === 'function') { callback(null, this.api) }
      })
    })
  } else {
    this.start(this.startingParams, (error) => {
      if (error) { this.api.log(error, 'error') }
      if (typeof callback === 'function') { callback(null, this.api) }
    })
  }
}

module.exports = actionhero
<|endoftext|>