<commit_before>import events from 'events'
import chalk from 'chalk'
import humanizeDuration from 'humanize-duration'

const DURATION_OPTIONS = {
    units: ['m', 's'],
    round: true,
    spacer: ''
}

/**
 * Initialize a new `spec` test reporter.
 *
 * @param {Runner} runner
 * @api public
 */
class SpecReporter extends events.EventEmitter {
    constructor (baseReporter, config, options = {}) {
        super()

        this.chalk = chalk
        this.baseReporter = baseReporter
        this.config = config
        this.options = options
        this.shortEnglishHumanizer = humanizeDuration.humanizer({
            language: 'shortEn',
            languages: { shortEn: {
                h: () => 'h',
                m: () => 'm',
                s: () => 's',
                ms: () => 'ms'
            }}
        })

        this.errorCount = 0
        this.indents = {}
        this.suiteIndents = {}
        this.specs = {}
        this.results = {}

        this.on('runner:start', function (runner) {
            this.suiteIndents[runner.cid] = {}
            this.indents[runner.cid] = 0
            this.specs[runner.cid] = runner.specs
            this.results[runner.cid] = {
                passing: 0,
                pending: 0,
                failing: 0
            }
        })

        this.on('suite:start', function (suite) {
            this.suiteIndents[suite.cid][suite.uid] = ++this.indents[suite.cid]
        })

        this.on('test:pending', function (test) {
            this.results[test.cid].pending++
        })

        this.on('test:pass', function (test) {
            this.results[test.cid].passing++
        })

        this.on('test:fail', function (test) {
            this.results[test.cid].failing++
        })

        this.on('suite:end', function (suite) {
            this.indents[suite.cid]--
        })

        this.on('runner:end', function (runner) {
            this.printSuiteResult(runner)
        })

        this.on('end', function () {
            this.printSuitesSummary()
        })
    }

    indent (cid, uid) {
        const indents = this.suiteIndents[cid][uid]
        return indents === 0 ? '' : Array(indents).join('    ')
    }

    getSymbol (state) {
        const { symbols } = this.baseReporter
        let symbol = '?' // in case of an unknown state

        switch (state) {
        case 'pass':
            symbol = symbols.ok
            break
        case 'pending':
            symbol = '-'
            break
        case 'fail':
            this.errorCount++
            symbol = this.errorCount + ')'
            break
        }

        return symbol
    }

    getColor (state) {
        let color = null // in case of an unknown state

        switch (state) {
        case 'pass':
        case 'passing':
            color = 'green'
            break
        case 'pending':
            color = 'cyan'
            break
        case 'fail':
        case 'failing':
            color = 'red'
            break
        }

        return color
    }

    getBrowserCombo (caps, verbose = true) {
        const device = caps.deviceName
        const browser = caps.browserName || caps.browser
        const version = caps.version || caps.platformVersion || caps.browser_version
        const platform = caps.os ? (caps.os + ' ' + caps.os_version) : (caps.platform || caps.platformName)

        /**
         * mobile capabilities
         */
        if (device) {
            const program = (caps.app || '').replace('sauce-storage:', '') || caps.browserName
            const executing = program ? `executing ${program}` : ''

            if (!verbose) {
                return `${device} ${platform} ${version}`
            }

            return `${device} on ${platform} ${version} ${executing}`.trim()
        }

        if (!verbose) {
            return (browser + ' ' + (version || '') + ' ' + (platform || '')).trim()
        }

        return browser + (version ? ` (v${version})` : '') + (platform ? ` on ${platform}` : '')
    }

    getResultList (cid, suites, preface = '') {
        let output = ''

        for (const specUid in suites) {
            // Remove "before all" tests from the displayed results
            if (specUid.indexOf('"before all"') === 0) {
                continue
            }

            const spec = suites[specUid]
            const indent = this.indent(cid, specUid)
            const specTitle = suites[specUid].title

            if (specUid.indexOf('"before all"') !== 0) {
                output += `${preface} ${indent}${specTitle}\n`
            }

            for (const testUid in spec.tests) {
                const test = spec.tests[testUid]
                const testTitle = spec.tests[testUid].title

                if (test.state === '') {
                    continue
                }

                output += preface
                output += '   ' + indent
                output += this.chalk[this.getColor(test.state)](this.getSymbol(test.state))
                output += ' ' + testTitle + '\n'
            }

            output += preface.trim() + '\n'
        }

        return output
    }

    getSummary (states, duration, preface = '') {
        let output = ''
        let displayedDuration = false

        for (const state in states) {
            const testCount = states[state]
            let testDuration = ''

            /**
             * don't display 0 passing/pending of failing test label
             */
            if (testCount === 0) {
                continue
            }

            /**
             * set duration
             */
            if (!displayedDuration) {
                testDuration = ' (' + this.shortEnglishHumanizer(duration, DURATION_OPTIONS) + ')'
            }

            output += preface + ' '
            output += this.chalk[this.getColor(state)](testCount)
            output += ' ' + this.chalk[this.getColor(state)](state)
            output += testDuration
            output += '\n'
            displayedDuration = true
        }

        return output
    }

    getFailureList (failures, preface) {
        let output = ''

        failures.forEach((test, i) => {
            const title = typeof test.parent !== 'undefined' ? test.parent + ' ' + test.title : test.title
            output += `${preface.trim()}\n`
            output += `${preface} ${(i + 1)}) ${title}:\n`
            output += `${preface} ${this.chalk.red(test.err.message)}\n`
            if (test.err.stack) {
                const stack = test.err.stack.split(/\n/g).map((l) => `${preface} ${this.chalk.gray(l)}`).join('\n')
                output += `${stack}\n`
            } else {
                output += `${preface} ${this.chalk.gray('no stack available')}\n`
            }
        })

        return output
    }

    getJobLink (results, preface) {
        if (!results.config.host) {
            return ''
        }

        let output = ''
        if (results.config.host.indexOf('saucelabs.com') > -1) {
            output += `${preface.trim()}\n`
            output += `${preface} Check out job at https://saucelabs.com/tests/${results.sessionID}\n`
            return output
        }

        return output
    }

    getSuiteResult (runner) {
        const cid = runner.cid
        const stats = this.baseReporter.stats
        const results = stats.runners[cid]
        const preface = `[${this.getBrowserCombo(results.capabilities, false)} #${cid}]`
        const specHash = stats.getSpecHash(runner)
        const spec = results.specs[specHash]
        const combo = this.getBrowserCombo(results.capabilities)
        const failures = stats.getFailures().filter((f) => f.cid === cid || Object.keys(f.runner).indexOf(cid) > -1)

        /**
         * don't print anything if no specs where executed
         */
        if (Object.keys(spec.suites).length === 0) {
            return ''
        }

        this.errorCount = 0
        let output = ''

        output += '------------------------------------------------------------------\n'

        /**
         * won't be available when running multiremote tests
         */
        if (results.sessionID) {
            output += `${preface} Session ID: ${results.sessionID}\n`
        }

        output += `${preface} Spec: ${this.specs[cid]}\n`

        /**
         * won't be available when running multiremote tests
         */
        if (combo) {
            output += `${preface} Running: ${combo}\n`
        }

        output += `${preface}\n`
        output += this.getResultList(cid, spec.suites, preface)
        output += `${preface}\n`
        output += this.getSummary(this.results[cid], spec._duration, preface)
        output += this.getFailureList(failures, preface)
        output += this.getJobLink(results, preface)
        output += `${preface}\n`
        return output
    }

    printSuiteResult (runner) {
        console.log(this.getSuiteResult(runner))
    }

    getSuitesSummary (specCount) {
        let output = '\n\n==================================================================\n'
        output += 'Number of specs: ' + specCount
        return output
    }

    printSuitesSummary () {
        const specCount = Object.keys(this.baseReporter.stats.runners).length

        /**
         * no need to print summary if only one runner was executed
         */
        if (specCount === 1) {
            return
        }

        const epilogue = this.baseReporter.epilogue
        console.log(this.getSuitesSummary(specCount))
        epilogue.call(this.baseReporter)
    }
}

export default SpecReporter
<commit_msg>Output saucelabs test url if using wdio-sauce-service<commit_after>import events from 'events'
import chalk from 'chalk'
import humanizeDuration from 'humanize-duration'

const DURATION_OPTIONS = {
    units: ['m', 's'],
    round: true,
    spacer: ''
}

/**
 * Initialize a new `spec` test reporter.
 *
 * @param {Runner} runner
 * @api public
 */
class SpecReporter extends events.EventEmitter {
    constructor (baseReporter, config, options = {}) {
        super()

        this.chalk = chalk
        this.baseReporter = baseReporter
        this.config = config
        this.options = options
        this.shortEnglishHumanizer = humanizeDuration.humanizer({
            language: 'shortEn',
            languages: { shortEn: {
                h: () => 'h',
                m: () => 'm',
                s: () => 's',
                ms: () => 'ms'
            }}
        })

        this.errorCount = 0
        this.indents = {}
        this.suiteIndents = {}
        this.specs = {}
        this.results = {}

        this.on('runner:start', function (runner) {
            this.suiteIndents[runner.cid] = {}
            this.indents[runner.cid] = 0
            this.specs[runner.cid] = runner.specs
            this.results[runner.cid] = {
                passing: 0,
                pending: 0,
                failing: 0
            }
        })

        this.on('suite:start', function (suite) {
            this.suiteIndents[suite.cid][suite.uid] = ++this.indents[suite.cid]
        })

        this.on('test:pending', function (test) {
            this.results[test.cid].pending++
        })

        this.on('test:pass', function (test) {
            this.results[test.cid].passing++
        })

        this.on('test:fail', function (test) {
            this.results[test.cid].failing++
        })

        this.on('suite:end', function (suite) {
            this.indents[suite.cid]--
        })

        this.on('runner:end', function (runner) {
            this.printSuiteResult(runner)
        })

        this.on('end', function () {
            this.printSuitesSummary()
        })
    }

    indent (cid, uid) {
        const indents = this.suiteIndents[cid][uid]
        return indents === 0 ? '' : Array(indents).join('    ')
    }

    getSymbol (state) {
        const { symbols } = this.baseReporter
        let symbol = '?' // in case of an unknown state

        switch (state) {
        case 'pass':
            symbol = symbols.ok
            break
        case 'pending':
            symbol = '-'
            break
        case 'fail':
            this.errorCount++
            symbol = this.errorCount + ')'
            break
        }

        return symbol
    }

    getColor (state) {
        let color = null // in case of an unknown state

        switch (state) {
        case 'pass':
        case 'passing':
            color = 'green'
            break
        case 'pending':
            color = 'cyan'
            break
        case 'fail':
        case 'failing':
            color = 'red'
            break
        }

        return color
    }

    getBrowserCombo (caps, verbose = true) {
        const device = caps.deviceName
        const browser = caps.browserName || caps.browser
        const version = caps.version || caps.platformVersion || caps.browser_version
        const platform = caps.os ? (caps.os + ' ' + caps.os_version) : (caps.platform || caps.platformName)

        /**
         * mobile capabilities
         */
        if (device) {
            const program = (caps.app || '').replace('sauce-storage:', '') || caps.browserName
            const executing = program ? `executing ${program}` : ''

            if (!verbose) {
                return `${device} ${platform} ${version}`
            }

            return `${device} on ${platform} ${version} ${executing}`.trim()
        }

        if (!verbose) {
            return (browser + ' ' + (version || '') + ' ' + (platform || '')).trim()
        }

        return browser + (version ? ` (v${version})` : '') + (platform ? ` on ${platform}` : '')
    }

    getResultList (cid, suites, preface = '') {
        let output = ''

        for (const specUid in suites) {
            // Remove "before all" tests from the displayed results
            if (specUid.indexOf('"before all"') === 0) {
                continue
            }

            const spec = suites[specUid]
            const indent = this.indent(cid, specUid)
            const specTitle = suites[specUid].title

            if (specUid.indexOf('"before all"') !== 0) {
                output += `${preface} ${indent}${specTitle}\n`
            }

            for (const testUid in spec.tests) {
                const test = spec.tests[testUid]
                const testTitle = spec.tests[testUid].title

                if (test.state === '') {
                    continue
                }

                output += preface
                output += '   ' + indent
                output += this.chalk[this.getColor(test.state)](this.getSymbol(test.state))
                output += ' ' + testTitle + '\n'
            }

            output += preface.trim() + '\n'
        }

        return output
    }

    getSummary (states, duration, preface = '') {
        let output = ''
        let displayedDuration = false

        for (const state in states) {
            const testCount = states[state]
            let testDuration = ''

            /**
             * don't display 0 passing/pending of failing test label
             */
            if (testCount === 0) {
                continue
            }

            /**
             * set duration
             */
            if (!displayedDuration) {
                testDuration = ' (' + this.shortEnglishHumanizer(duration, DURATION_OPTIONS) + ')'
            }

            output += preface + ' '
            output += this.chalk[this.getColor(state)](testCount)
            output += ' ' + this.chalk[this.getColor(state)](state)
            output += testDuration
            output += '\n'
            displayedDuration = true
        }

        return output
    }

    getFailureList (failures, preface) {
        let output = ''

        failures.forEach((test, i) => {
            const title = typeof test.parent !== 'undefined' ? test.parent + ' ' + test.title : test.title
            output += `${preface.trim()}\n`
            output += `${preface} ${(i + 1)}) ${title}:\n`
            output += `${preface} ${this.chalk.red(test.err.message)}\n`
            if (test.err.stack) {
                const stack = test.err.stack.split(/\n/g).map((l) => `${preface} ${this.chalk.gray(l)}`).join('\n')
                output += `${stack}\n`
            } else {
                output += `${preface} ${this.chalk.gray('no stack available')}\n`
            }
        })

        return output
    }

    getJobLink (results, preface) {
        if (!results.config.host) {
            return ''
        }

        let output = ''
        if (results.config.host.indexOf('saucelabs.com') > -1 || results.config.sauceConnect === true) {
            output += `${preface.trim()}\n`
            output += `${preface} Check out job at https://saucelabs.com/tests/${results.sessionID}\n`
            return output
        }

        return output
    }

    getSuiteResult (runner) {
        const cid = runner.cid
        const stats = this.baseReporter.stats
        const results = stats.runners[cid]
        const preface = `[${this.getBrowserCombo(results.capabilities, false)} #${cid}]`
        const specHash = stats.getSpecHash(runner)
        const spec = results.specs[specHash]
        const combo = this.getBrowserCombo(results.capabilities)
        const failures = stats.getFailures().filter((f) => f.cid === cid || Object.keys(f.runner).indexOf(cid) > -1)

        /**
         * don't print anything if no specs where executed
         */
        if (Object.keys(spec.suites).length === 0) {
            return ''
        }

        this.errorCount = 0
        let output = ''

        output += '------------------------------------------------------------------\n'

        /**
         * won't be available when running multiremote tests
         */
        if (results.sessionID) {
            output += `${preface} Session ID: ${results.sessionID}\n`
        }

        output += `${preface} Spec: ${this.specs[cid]}\n`

        /**
         * won't be available when running multiremote tests
         */
        if (combo) {
            output += `${preface} Running: ${combo}\n`
        }

        output += `${preface}\n`
        output += this.getResultList(cid, spec.suites, preface)
        output += `${preface}\n`
        output += this.getSummary(this.results[cid], spec._duration, preface)
        output += this.getFailureList(failures, preface)
        output += this.getJobLink(results, preface)
        output += `${preface}\n`
        return output
    }

    printSuiteResult (runner) {
        console.log(this.getSuiteResult(runner))
    }

    getSuitesSummary (specCount) {
        let output = '\n\n==================================================================\n'
        output += 'Number of specs: ' + specCount
        return output
    }

    printSuitesSummary () {
        const specCount = Object.keys(this.baseReporter.stats.runners).length

        /**
         * no need to print summary if only one runner was executed
         */
        if (specCount === 1) {
            return
        }

        const epilogue = this.baseReporter.epilogue
        console.log(this.getSuitesSummary(specCount))
        epilogue.call(this.baseReporter)
    }
}

export default SpecReporter
<|endoftext|>


<commit_before>/* eslint-disable */
var loaded = function(win, fn) {
	var done = false;
	var top = true;

	var doc = win.document;
	var root = doc.documentElement;
	var modern = doc.addEventListener;

	var add = modern ? 'addEventListener' : 'attachEvent';
	var rem = modern ? 'removeEventListener' : 'detachEvent';
	var pre = modern ? '' : 'on';

	var init = function(e) {
		if (e.type == 'readystatechange' && doc.readyState != 'complete') return;
		(e.type == 'load' ? win : doc)[rem](pre + e.type, init, false);
		if (!done && (done = true)) fn.call(win, e.type || e);
	};

	var poll = function() {
		try { root.doScroll('left'); } catch(e) { setTimeout(poll, 50); return; }
		init('poll');
	};

	if (doc.readyState == 'complete') fn.call(win, 'lazy');
	else {
		if (!modern && root.doScroll) {
			try { top = !win.frameElement; } catch(e) { }
			if (top) poll();
		}
		doc[add](pre + 'DOMContentLoaded', init, false);
		doc[add](pre + 'readystatechange', init, false);
		win[add](pre + 'load', init, false);
	}
};

export default loaded;
<commit_msg>site-search-overlay: format loaded code<commit_after>/* eslint-disable */
const loaded = function(win, fn) {
  let done = false;
  let top = true;

  const doc = win.document;
  const root = doc.documentElement;
  const modern = doc.addEventListener;

  const add = modern ? "addEventListener" : "attachEvent";
  const rem = modern ? "removeEventListener" : "detachEvent";
  const pre = modern ? "" : "on";

  const init = function(e) {
    if (e.type == "readystatechange" && doc.readyState != "complete") return;
    (e.type == "load" ? win : doc)[rem](pre + e.type, init, false);
    if (!done) {
      done = true;
      fn.call(win, e.type || e);
    }
  };

  const poll = function() {
    try {
      root.doScroll("left");
    } catch (e) {
      setTimeout(poll, 50);
      return;
    }
    init("poll");
  };

  if (doc.readyState == "complete") fn.call(win, "lazy");
  else {
    if (!modern && root.doScroll) {
      try {
        top = !win.frameElement;
      } catch (e) {}
      if (top) poll();
    }
    doc[add](pre + "DOMContentLoaded", init, false);
    doc[add](pre + "readystatechange", init, false);
    win[add](pre + "load", init, false);
  }
};

export default loaded;
<|endoftext|>


<commit_before>var util = require('util');
var u = require('./util');

var BaseReporter = function(adapter) {
  this.adapters = [adapter || process.stdout.write.bind(process.stdout)];

  this.renderBrowser = function(browser) {
    var results = browser.lastResult;
    var totalExecuted = results.success + results.failed;
    var msg = util.format('%s: Executed %d of %d', browser, totalExecuted, results.total);

    if (results.failed) {
      msg += util.format(this.X_FAILED, results.failed);
    }

    if (results.skipped) {
      msg += util.format(' (skipped %d)', results.skipped);
    }

    if (browser.isReady) {
      if (results.disconnected) {
        msg += this.FINISHED_DISCONNECTED;
      } else if (results.error) {
        msg += this.FINISHED_ERROR;
      } else if (!results.failed) {
        msg += this.FINISHED_SUCCESS;
      }
    }

    return msg;
  };

  this.renderBrowser = this.renderBrowser.bind(this);

  this.write = function() {
    var msg = util.format.apply(null, Array.prototype.slice.call(arguments));

    this.adapters.forEach(function(adapter) {
      adapter(msg);
    });
  };

  this.writeCommonMsg = this.write;

  this.onRunStart = function(browsers) {
    this.browsers_ = browsers;
  };

  this.onBrowserError = function(browser, error) {
    this.writeCommonMsg(util.format(this.ERROR, browser) + u.formatError(error, '\t'));
  };

  this.onBrowserDump = function(browser, dump) {
    var msg = browser + ' DUMP: ';

    if (dump.length > 1) {
      msg += dump.length + ' entries\n' + dump.join('\n');
    } else {
      msg += dump[0];
    }

    this.writeCommonMsg(msg + '\n');
  };

  this.onSpecComplete = function(browser, result) {
    if (result.skipped) this.specSkipped(browser, result);
    else if (result.success) this.specSuccess(browser, result);
    else this.specFailure(browser, result);
  };

  this.specSuccess = this.specSkipped = function() {};

  this.specFailure = function(browser, result) {
    var specName = result.suite.join(' ') + ' ' + result.description;
    var msg = util.format(this.SPEC_FAILURE, browser, specName);

    result.log.forEach(function(log) {
      msg += u.formatError(log, '\t');
    });

    this.writeCommonMsg(msg);
  };

  this.onRunComplete = function(browsers, results) {
    if (browsers.length > 1) {
      if (!results.failed) {
        this.write(this.TOTAL_SUCCESS, results.success);
      } else {
        this.write(this.TOTAL_FAILED, results.failed, results.success);
      }
    }
  };

  this.SPEC_FAILURE = '%s %s FAILED' + '\n';
  this.ERROR = '%s ERROR\n';

  this.FINISHED_ERROR = ' ERROR';
  this.FINISHED_SUCCESS = ' SUCCESS';
  this.FINISHED_DISCONNECTED = ' DISCONNECTED';

  this.X_FAILED = ' (%d FAILED)';

  this.TOTAL_SUCCESS = 'TOTAL: %d SUCCESS\n';
  this.TOTAL_FAILED = 'TOTAL: %d FAILED, %d SUCCESS\n';
};

var BaseColorReporter = function() {
  this.SPEC_FAILURE = '\033[31m%s %s FAILED\033[39m' + '\n';
  this.ERROR = '\033[31m%s ERROR\033[39m\n';

  this.FINISHED_ERROR = ' \033[31mERROR\033[39m';
  this.FINISHED_SUCCESS = ' \033[32mSUCCESS\033[39m';
  this.FINISHED_DISCONNECTED = ' \033[31mDISCONNECTED\033[39m';

  this.X_FAILED = ' \033[31m(%d FAILED)\033[39m';

  this.TOTAL_SUCCESS = '\033[32mTOTAL: %d SUCCESS\033[39m\n';
  this.TOTAL_FAILED = '\033[31mTOTAL: %d FAILED, %d SUCCESS\033[39m\n';
};

var ProgressReporter = function(adapter) {
  BaseReporter.call(this, adapter);

  this.writeCommonMsg = function(msg) {
    this.write(this.remove_() + msg + this.render_());
  };

  this.specSuccess = function(browser) {
    this.write(this.refresh_());
  };

  this.onBrowserComplete = function(browser) {
    this.write(this.refresh_());
  };

  this.onRunStart = function(browsers) {
    this.browsers_ = browsers;
    this.isRendered_ = false;
  };

  this.remove_ = function() {
    if (!this.isRendered_) return '';

    var cmd = '';
    this.browsers_.forEach(function() {
      cmd += '\033[1A' + '\033[2K';
    });

    this.isRendered_ = false;

    return cmd;
  };

  this.render_ = function() {
    this.isRendered_ = true;

    return this.browsers_.map(this.renderBrowser).join('\n') + '\n';
  };

  this.refresh_ = function() {
    return this.remove_() + this.render_();
  };
};

var DotsReporter = function(adapter) {
  BaseReporter.call(this, adapter);

  this.writeCommonMsg = function(msg) {
    this.write('\n' + msg);
  };

  this.specSuccess = function() {
    this.write('.');
  };

  this.onBrowserComplete = function(browser) {
    this.writeCommonMsg(this.browsers_.map(this.renderBrowser).join('\n') + '\n');
  };
};

var DotsColorReporter = function() {
  DotsReporter.call(this);
  BaseColorReporter.call(this);
};

var ProgressColorReporter = function() {
  ProgressReporter.call(this);
  BaseColorReporter.call(this);
};

// PUBLISH
exports.Dots = DotsReporter;
exports.Progress = ProgressReporter;
exports.DotsColor = DotsColorReporter;
exports.ProgressColor = ProgressColorReporter;

exports.createReporter = function(name, useColors) {
  return new exports[u.ucFirst(name) + (useColors ? 'Color' : '')]();
};
<commit_msg>DOTS reporter - wrap at 80<commit_after>var util = require('util');
var u = require('./util');

var BaseReporter = function(adapter) {
  this.adapters = [adapter || process.stdout.write.bind(process.stdout)];

  this.renderBrowser = function(browser) {
    var results = browser.lastResult;
    var totalExecuted = results.success + results.failed;
    var msg = util.format('%s: Executed %d of %d', browser, totalExecuted, results.total);

    if (results.failed) {
      msg += util.format(this.X_FAILED, results.failed);
    }

    if (results.skipped) {
      msg += util.format(' (skipped %d)', results.skipped);
    }

    if (browser.isReady) {
      if (results.disconnected) {
        msg += this.FINISHED_DISCONNECTED;
      } else if (results.error) {
        msg += this.FINISHED_ERROR;
      } else if (!results.failed) {
        msg += this.FINISHED_SUCCESS;
      }
    }

    return msg;
  };

  this.renderBrowser = this.renderBrowser.bind(this);

  this.write = function() {
    var msg = util.format.apply(null, Array.prototype.slice.call(arguments));

    this.adapters.forEach(function(adapter) {
      adapter(msg);
    });
  };

  this.writeCommonMsg = this.write;

  this.onBrowserError = function(browser, error) {
    this.writeCommonMsg(util.format(this.ERROR, browser) + u.formatError(error, '\t'));
  };

  this.onBrowserDump = function(browser, dump) {
    var msg = browser + ' DUMP: ';

    if (dump.length > 1) {
      msg += dump.length + ' entries\n' + dump.join('\n');
    } else {
      msg += dump[0];
    }

    this.writeCommonMsg(msg + '\n');
  };

  this.onSpecComplete = function(browser, result) {
    if (result.skipped) this.specSkipped(browser, result);
    else if (result.success) this.specSuccess(browser, result);
    else this.specFailure(browser, result);
  };

  this.specSuccess = this.specSkipped = function() {};

  this.specFailure = function(browser, result) {
    var specName = result.suite.join(' ') + ' ' + result.description;
    var msg = util.format(this.SPEC_FAILURE, browser, specName);

    result.log.forEach(function(log) {
      msg += u.formatError(log, '\t');
    });

    this.writeCommonMsg(msg);
  };

  this.onRunComplete = function(browsers, results) {
    if (browsers.length > 1) {
      if (!results.failed) {
        this.write(this.TOTAL_SUCCESS, results.success);
      } else {
        this.write(this.TOTAL_FAILED, results.failed, results.success);
      }
    }
  };

  this.SPEC_FAILURE = '%s %s FAILED' + '\n';
  this.ERROR = '%s ERROR\n';

  this.FINISHED_ERROR = ' ERROR';
  this.FINISHED_SUCCESS = ' SUCCESS';
  this.FINISHED_DISCONNECTED = ' DISCONNECTED';

  this.X_FAILED = ' (%d FAILED)';

  this.TOTAL_SUCCESS = 'TOTAL: %d SUCCESS\n';
  this.TOTAL_FAILED = 'TOTAL: %d FAILED, %d SUCCESS\n';
};

var BaseColorReporter = function() {
  this.SPEC_FAILURE = '\033[31m%s %s FAILED\033[39m' + '\n';
  this.ERROR = '\033[31m%s ERROR\033[39m\n';

  this.FINISHED_ERROR = ' \033[31mERROR\033[39m';
  this.FINISHED_SUCCESS = ' \033[32mSUCCESS\033[39m';
  this.FINISHED_DISCONNECTED = ' \033[31mDISCONNECTED\033[39m';

  this.X_FAILED = ' \033[31m(%d FAILED)\033[39m';

  this.TOTAL_SUCCESS = '\033[32mTOTAL: %d SUCCESS\033[39m\n';
  this.TOTAL_FAILED = '\033[31mTOTAL: %d FAILED, %d SUCCESS\033[39m\n';
};

var ProgressReporter = function(adapter) {
  BaseReporter.call(this, adapter);

  this.writeCommonMsg = function(msg) {
    this.write(this.remove_() + msg + this.render_());
  };

  this.specSuccess = function(browser) {
    this.write(this.refresh_());
  };

  this.onBrowserComplete = function(browser) {
    this.write(this.refresh_());
  };

  this.onRunStart = function(browsers) {
    this.browsers_ = browsers;
    this.isRendered_ = false;
  };

  this.remove_ = function() {
    if (!this.isRendered_) return '';

    var cmd = '';
    this.browsers_.forEach(function() {
      cmd += '\033[1A' + '\033[2K';
    });

    this.isRendered_ = false;

    return cmd;
  };

  this.render_ = function() {
    this.isRendered_ = true;

    return this.browsers_.map(this.renderBrowser).join('\n') + '\n';
  };

  this.refresh_ = function() {
    return this.remove_() + this.render_();
  };
};

var DotsReporter = function(adapter) {
  BaseReporter.call(this, adapter);

  var DOTS_WRAP = 80;

  this.onRunStart = function(browsers) {
    this.browsers_ = browsers;
    this.dotsCount_ = 0;
  };

  this.writeCommonMsg = function(msg) {
    this.write('\n' + msg);
    this.dotsCount_ = 0;
  };

  this.specSuccess = function() {
    this.dotsCount_ = (this.dotsCount_ + 1) % DOTS_WRAP;
    this.write(this.dotsCount_ ? '.' : '.\n');
  };

  this.onBrowserComplete = function(browser) {
    this.writeCommonMsg(this.browsers_.map(this.renderBrowser).join('\n') + '\n');
  };
};

var DotsColorReporter = function() {
  DotsReporter.call(this);
  BaseColorReporter.call(this);
};

var ProgressColorReporter = function() {
  ProgressReporter.call(this);
  BaseColorReporter.call(this);
};

// PUBLISH
exports.Dots = DotsReporter;
exports.Progress = ProgressReporter;
exports.DotsColor = DotsColorReporter;
exports.ProgressColor = ProgressColorReporter;

exports.createReporter = function(name, useColors) {
  return new exports[u.ucFirst(name) + (useColors ? 'Color' : '')]();
};
<|endoftext|>


<commit_before>var _ = require("underscore");
var path = require("path");
var semver = require("semver");
var findFiles = require("./utils/find_files");
var path = require("path");
var Parser = require("./parser");
var Worker = require("./worker");
var Filter = require("./filter");
var markdown = require("marked");
var colors = require("colors");
var fs = require("fs-extra");

// Options
var _defaultOptions = {
	excludeFilters: [],
	includeFilters: [ ".*\\.(coffee|cs|dart|erl|go|java|js|php?|py|rb|ts)$" ],

	src: path.join(__dirname, "../example/"),
	dest: path.join(__dirname, "../doc/"),

	debug: false,
	log: true,
	simulate: false,

	template: path.join(__dirname, "../template/"),

	filters: {},
	parsers: {},
	workers: {},

	marked: {
		gfm:         true,
		tables:      true,
		breaks:      false,
		pedantic:    false,
		sanitize:    false,
		smartLists:  false,
		smartypants: false
	}
};

var options = {};
_.defaults(options, _defaultOptions);

// uncaughtException
process.on("uncaughtException", function(err) {
	console.error((new Date()).toUTCString() + " uncaughtException:", err.message);
	console.error(err.stack);
	process.exit(1);
});

/**
 * Output Debug-Messages
 *
 * @param {String} message
 */
function debug(message)
{
	if(options.debug) console.log("apidoc: " + message);
} // debug

/**
 * Output Log-Messages
 *
 * @param {String} message
 */
function log(message)
{
	if(options.log) console.log("apidoc: " + message);
} // log

/**
 * Output Error-Log-Messages
 *
 * @param {String} message
 */
function logWarn(message)
{
	if(options.log) console.warn("apidoc: " + message.yellow);
} // logWarn

var app = {
	debug: debug,
	log: log,
	logWarn: logWarn,
	filters: {
		apierror                 : "./plugins/filter_api_error.js",
		apiinfo                  : "./plugins/filter_api_info.js",
		apiparam                 : "./plugins/filter_api_param.js",
		apisuccess               : "./plugins/filter_api_success.js"
	},
	parsers: {
		api                      : "./plugins/parser_api.js",
		apidefineerrorstructure  : "./plugins/parser_api_define_error_structure.js",
		apidefinepermission      : "./plugins/parser_api_define_permission.js",
		apidefinestructure       : "./plugins/parser_api_define_structure.js",
		apidefinesuccessstructure: "./plugins/parser_api_define_success_structure.js",
		apidescription           : "./plugins/parser_api_description.js",
		apierror                 : "./plugins/parser_api_error.js",
		apierrorexample          : "./plugins/parser_api_error_example.js",
		apierrorstructure        : "./plugins/parser_api_error_structure.js",
		apierrortitle            : "./plugins/parser_api_error_title.js",
		apiexample               : "./plugins/parser_api_example.js",
		apigroup                 : "./plugins/parser_api_group.js",
		apiinfo                  : "./plugins/parser_api_info.js",
		apiinfoexample           : "./plugins/parser_api_info_example.js",
		apiinfotitle             : "./plugins/parser_api_info_title.js",
		apiname                  : "./plugins/parser_api_name.js",
		apiparam                 : "./plugins/parser_api_param.js",
		apiparamtitle            : "./plugins/parser_api_param_title.js",
		apipermission            : "./plugins/parser_api_permission.js",
		apistructure             : "./plugins/parser_api_structure.js",
		apisuccess               : "./plugins/parser_api_success.js",
		apisuccessexample        : "./plugins/parser_api_success_example.js",
		apisuccessstructure      : "./plugins/parser_api_success_structure.js",
		apisuccesstitle          : "./plugins/parser_api_success_title.js",
		apiversion               : "./plugins/parser_api_version.js"
	},
	workers: {
		workererrorstructure     : "./plugins/worker_error_structure.js",
		workererrortitle         : "./plugins/worker_error_title.js",
		workerinfotitle          : "./plugins/worker_info_title.js",
		workerpermission         : "./plugins/worker_permission.js",
		workerstructure          : "./plugins/worker_structure.js",
		workerparamtitle         : "./plugins/worker_param_title.js",
		workersuccessstructure   : "./plugins/worker_success_structure.js",
		workersuccesstitle       : "./plugins/worker_success_title.js"
	}
}; // app

/**
 * Read package.json Data and optianl descriptions
 */
function getPackageData()
{
	var packageInfos = {};
	try
	{
		var filename = path.join(options.src, "package.json");
		if( ! fs.existsSync(filename))
		{
			filename = "./package.json";
		}
		var json = JSON.parse( fs.readFileSync(filename, "utf8") );
		app.debug("read: " + filename);

		packageInfos.name = json.name;
		packageInfos.version = json.version;
		packageInfos.description = json.description;
		packageInfos.apidoc = json.apidoc || "";

		if(json.apidocFilename)
		{
			var filename = path.join(options.src, json.apidocFilename);
			if( ! fs.existsSync(filename))
			{
				filename = path.join("./", json.apidocFilename);
			}
			packageInfos.apidoc = fs.readFileSync(filename, "utf8");
			app.debug("read: " + filename);
		}
	}
	catch(e) {
		app.debug("No package.json found!");
		packageInfos.apidoc = "";
	}

	// Generator Information
	try
	{
		var apidocPath = path.join(__dirname, "../");
		var json = JSON.parse( fs.readFileSync(apidocPath + "package.json", "utf8") );
		packageInfos.generator = {
			version: json.version,
			time: new Date()
		};
	}
	catch(e) {}

	// Markdown to HTML
	packageInfos.apidoc = markdown(packageInfos.apidoc);

	return packageInfos;
} // getPackageData

/**
 * Output parsed content to files
 *
 * @param {Object[]} parsedFiles
 * @param {String[]} filenames
 * @returns {Object}
 */
function createOutputFiles(parsedFiles, parsedFilenames, packageInfos)
{
	var blocks = [];
	// Reduce to get only local blocks.
	for(var fileIndex = 0; fileIndex < parsedFiles.length; fileIndex += 1)
	{
		var parsedFile = parsedFiles[fileIndex];
		for(var blockIndex = 0; blockIndex < parsedFile.length; blockIndex += 1)
		{
			var block = parsedFile[blockIndex];
			// "<= 1" if successTitle gets removed, empty Object remain.
			if(Object.keys(block.global).length <= 1 && Object.keys(block.local).length > 0)
			{
				// Add needed Elements for sorting
				if( ! block.local.group) block.local.group = path.basename( parsedFilenames[fileIndex] );
				if( ! block.local.type) block.local.type = "";
				if( ! block.local.url) block.local.url = "";
				if( ! block.local.version) block.local.version = "0.0.0";

				// Info Element
				if( ! block.local.filename) block.local.filename = parsedFilenames[fileIndex];

				blocks.push(block.local);
			}
		} // for blockIndex
	} // for fileIndex

	// Empty
	parsedFiles = null;
	parsedFilenames = null;

	// Sort by group ASC, name ASC, version DESC
	blocks.sort(function(a, b) {
		var nameA = a.group + a.name;
		var nameB = b.group + b.name;

		if(nameA === nameB)
		{
			if(a.version === b.version) return 0;
			return (semver.gte(a.version, b.version)) ? -1 : 1;
		}
		return (nameA < nameB) ? -1 : 1;
	});

	if(options.simulate)
	{
		app.debug("");
		app.debug("!!! Simulation !!! No file or dir will be copied or created.");
		app.debug("");
	}

	app.debug("create dir: " + options.dest);
	if( ! options.simulate) fs.mkdirsSync(options.dest);

	app.debug("copy template " + options.template + " to: " + options.dest);
	if( ! options.simulate) fs.copySync(options.template, options.dest);

	// api_data
	var json = JSON.stringify(blocks, null, 2);
	app.debug("write json file: " + options.dest + "api_data.json");
	if( ! options.simulate) fs.writeFileSync(options.dest + "./api_data.json", json);

	app.debug("write js file: " + options.dest + "api_data.js");
	if( ! options.simulate) fs.writeFileSync(options.dest + "./api_data.js", "define({ api: " + json + " });");

	// api_project
	var json = JSON.stringify(packageInfos, null, 2);
	app.debug("write json file: " + options.dest + "api_project.json");
	if( ! options.simulate) fs.writeFileSync(options.dest + "./api_project.json", json);

	app.debug("write js file: " + options.dest + "api_project.js");
	if( ! options.simulate) fs.writeFileSync(options.dest + "./api_project.js", "define(" + json + ");");
} // createOutputFiles

/**
 * Main
 *
 * @return {Number} Count parsed files.
 */
function main(defaults)
{
	// bin-parameters
	if(defaults) options = _.defaults(defaults, options);

	// marked (markdown) Settings.
	markdown.setOptions(options.marked);

	// Paths
	options.src      = path.join(options.src, "./");
	options.dest     = path.join(options.dest, "./");
	options.template = path.join(options.template, "./");

	// Funktionen erweitern / ersetzen
	_.defaults(options.logger, app.logger);
	_.defaults(options.filters, app.filters);
	_.defaults(options.parsers, app.parsers);
	_.defaults(options.workers, app.workers);

	var files = findFiles(options);
	var parser = new Parser(app);
	var parsedFiles = [];
	var parsedFilenames = [];
	var worker = new Worker(app);
	var filter = new Filter(app);

	try
	{
		// Parser
		for(var i = 0; i < files.length; i += 1)
		{
			var filename = options.src + files[i];
			var parsedFile = parser.parseFile(filename);
			if(parsedFile)
			{
				app.log("parse file: " + filename);

				parsedFiles.push(parsedFile);
				parsedFilenames.push(filename);
			}
		} // for

		// Worker / Filter
		if(parsedFiles.length > 0)
		{
			worker.process(parsedFiles, parsedFilenames);
			filter.process(parsedFiles, parsedFilenames);

			var packageInfos = getPackageData();
			createOutputFiles(parsedFiles, parsedFilenames, packageInfos);

			return parsedFiles.length;
		}
		else
		{
			app.log("Nothing to do.");
			return 0;
		}
	}
	catch(e)
	{
		if(e.stack) app.debug(e.stack);
		app.log(e);
	}
	return;
} // main

/**
 * Exports
 */
module.exports = main;

// Direct call
if(path.dirname(process.argv[1]) === __dirname) main();
<commit_msg>Support for multiple input folders.  When multiple entries are provided for "-i" in options, all provided folders will be parsed in the order provided.<commit_after>var _ = require("underscore");
var path = require("path");
var semver = require("semver");
var findFiles = require("./utils/find_files");
var path = require("path");
var Parser = require("./parser");
var Worker = require("./worker");
var Filter = require("./filter");
var markdown = require("marked");
var colors = require("colors");
var fs = require("fs-extra");

// Options
var _defaultOptions = {
	excludeFilters: [],
	includeFilters: [ ".*\\.(coffee|cs|dart|erl|go|java|js|php?|py|rb|ts)$" ],

	src: path.join(__dirname, "../example/"),
	dest: path.join(__dirname, "../doc/"),

	debug: false,
	log: true,
	simulate: false,

	template: path.join(__dirname, "../template/"),

	filters: {},
	parsers: {},
	workers: {},

	marked: {
		gfm:         true,
		tables:      true,
		breaks:      false,
		pedantic:    false,
		sanitize:    false,
		smartLists:  false,
		smartypants: false
	}
};

var options = {};
_.defaults(options, _defaultOptions);

// uncaughtException
process.on("uncaughtException", function(err) {
	console.error((new Date()).toUTCString() + " uncaughtException:", err.message);
	console.error(err.stack);
	process.exit(1);
});

/**
 * Output Debug-Messages
 *
 * @param {String} message
 */
function debug(message)
{
	if(options.debug) console.log("apidoc: " + message);
} // debug

/**
 * Output Log-Messages
 *
 * @param {String} message
 */
function log(message)
{
	if(options.log) console.log("apidoc: " + message);
} // log

/**
 * Output Error-Log-Messages
 *
 * @param {String} message
 */
function logWarn(message)
{
	if(options.log) console.warn("apidoc: " + message.yellow);
} // logWarn

var app = {
	debug: debug,
	log: log,
	logWarn: logWarn,
	filters: {
		apierror                 : "./plugins/filter_api_error.js",
		apiinfo                  : "./plugins/filter_api_info.js",
		apiparam                 : "./plugins/filter_api_param.js",
		apisuccess               : "./plugins/filter_api_success.js"
	},
	parsers: {
		api                      : "./plugins/parser_api.js",
		apidefineerrorstructure  : "./plugins/parser_api_define_error_structure.js",
		apidefinepermission      : "./plugins/parser_api_define_permission.js",
		apidefinestructure       : "./plugins/parser_api_define_structure.js",
		apidefinesuccessstructure: "./plugins/parser_api_define_success_structure.js",
		apidescription           : "./plugins/parser_api_description.js",
		apierror                 : "./plugins/parser_api_error.js",
		apierrorexample          : "./plugins/parser_api_error_example.js",
		apierrorstructure        : "./plugins/parser_api_error_structure.js",
		apierrortitle            : "./plugins/parser_api_error_title.js",
		apiexample               : "./plugins/parser_api_example.js",
		apigroup                 : "./plugins/parser_api_group.js",
		apiinfo                  : "./plugins/parser_api_info.js",
		apiinfoexample           : "./plugins/parser_api_info_example.js",
		apiinfotitle             : "./plugins/parser_api_info_title.js",
		apiname                  : "./plugins/parser_api_name.js",
		apiparam                 : "./plugins/parser_api_param.js",
		apiparamtitle            : "./plugins/parser_api_param_title.js",
		apipermission            : "./plugins/parser_api_permission.js",
		apistructure             : "./plugins/parser_api_structure.js",
		apisuccess               : "./plugins/parser_api_success.js",
		apisuccessexample        : "./plugins/parser_api_success_example.js",
		apisuccessstructure      : "./plugins/parser_api_success_structure.js",
		apisuccesstitle          : "./plugins/parser_api_success_title.js",
		apiversion               : "./plugins/parser_api_version.js"
	},
	workers: {
		workererrorstructure     : "./plugins/worker_error_structure.js",
		workererrortitle         : "./plugins/worker_error_title.js",
		workerinfotitle          : "./plugins/worker_info_title.js",
		workerpermission         : "./plugins/worker_permission.js",
		workerstructure          : "./plugins/worker_structure.js",
		workerparamtitle         : "./plugins/worker_param_title.js",
		workersuccessstructure   : "./plugins/worker_success_structure.js",
		workersuccesstitle       : "./plugins/worker_success_title.js"
	}
}; // app

/**
 * Read package.json Data and optianl descriptions
 */
function getPackageData()
{
	var packageInfos = {};
	try
	{
		var filename = path.join(options.src, "package.json");
		if( ! fs.existsSync(filename))
		{
			filename = "./package.json";
		}
		var json = JSON.parse( fs.readFileSync(filename, "utf8") );
		app.debug("read: " + filename);

		packageInfos.name = json.name;
		packageInfos.version = json.version;
		packageInfos.description = json.description;
		packageInfos.apidoc = json.apidoc || "";

		if(json.apidocFilename)
		{
			var filename = path.join(options.src, json.apidocFilename);
			if( ! fs.existsSync(filename))
			{
				filename = path.join("./", json.apidocFilename);
			}
			packageInfos.apidoc = fs.readFileSync(filename, "utf8");
			app.debug("read: " + filename);
		}
	}
	catch(e) {
		app.debug("No package.json found!");
		packageInfos.apidoc = "";
	}

	// Generator Information
	try
	{
		var apidocPath = path.join(__dirname, "../");
		var json = JSON.parse( fs.readFileSync(apidocPath + "package.json", "utf8") );
		packageInfos.generator = {
			version: json.version,
			time: new Date()
		};
	}
	catch(e) {}

	// Markdown to HTML
	packageInfos.apidoc = markdown(packageInfos.apidoc);

	return packageInfos;
} // getPackageData

/**
 * Output parsed content to files
 *
 * @param {Object[]} parsedFiles
 * @param {String[]} filenames
 * @returns {Object}
 */
function createOutputFiles(parsedFiles, parsedFilenames, packageInfos)
{
	var blocks = [];
	// Reduce to get only local blocks.
	for(var fileIndex = 0; fileIndex < parsedFiles.length; fileIndex += 1)
	{
		var parsedFile = parsedFiles[fileIndex];
		for(var blockIndex = 0; blockIndex < parsedFile.length; blockIndex += 1)
		{
			var block = parsedFile[blockIndex];
			// "<= 1" if successTitle gets removed, empty Object remain.
			if(Object.keys(block.global).length <= 1 && Object.keys(block.local).length > 0)
			{
				// Add needed Elements for sorting
				if( ! block.local.group) block.local.group = path.basename( parsedFilenames[fileIndex] );
				if( ! block.local.type) block.local.type = "";
				if( ! block.local.url) block.local.url = "";
				if( ! block.local.version) block.local.version = "0.0.0";

				// Info Element
				if( ! block.local.filename) block.local.filename = parsedFilenames[fileIndex];

				blocks.push(block.local);
			}
		} // for blockIndex
	} // for fileIndex

	// Empty
	parsedFiles = null;
	parsedFilenames = null;

	// Sort by group ASC, name ASC, version DESC
	blocks.sort(function(a, b) {
		var nameA = a.group + a.name;
		var nameB = b.group + b.name;

		if(nameA === nameB)
		{
			if(a.version === b.version) return 0;
			return (semver.gte(a.version, b.version)) ? -1 : 1;
		}
		return (nameA < nameB) ? -1 : 1;
	});

	if(options.simulate)
	{
		app.debug("");
		app.debug("!!! Simulation !!! No file or dir will be copied or created.");
		app.debug("");
	}

	app.debug("create dir: " + options.dest);
	if( ! options.simulate) fs.mkdirsSync(options.dest);

	app.debug("copy template " + options.template + " to: " + options.dest);
	if( ! options.simulate) fs.copySync(options.template, options.dest);

	// api_data
	var json = JSON.stringify(blocks, null, 2);
	app.debug("write json file: " + options.dest + "api_data.json");
	if( ! options.simulate) fs.writeFileSync(options.dest + "./api_data.json", json);

	app.debug("write js file: " + options.dest + "api_data.js");
	if( ! options.simulate) fs.writeFileSync(options.dest + "./api_data.js", "define({ api: " + json + " });");

	// api_project
	var json = JSON.stringify(packageInfos, null, 2);
	app.debug("write json file: " + options.dest + "api_project.json");
	if( ! options.simulate) fs.writeFileSync(options.dest + "./api_project.json", json);

	app.debug("write js file: " + options.dest + "api_project.js");
	if( ! options.simulate) fs.writeFileSync(options.dest + "./api_project.js", "define(" + json + ");");
} // createOutputFiles

/**
 * Parse files in specified folder.
 * @param {Object} parser Util to parse the files.
 * @param {Object} options The options used to parse and filder the files.
 * @param {Object[]} parsedFiles List of parsed files.
 * @param {String[]} parsedFilenames List of parsed files, with full path.
 */
function parseFiles(parser, options, parsedFiles, parsedFilenames)
{
    var files = findFiles(options);
	// Parser
	for(var i = 0; i < files.length; i += 1)
	{
	  	var filename = options.src + files[i];
	   	var parsedFile = parser.parseFile(filename);
	   	if(parsedFile)
	   	{
	 	   app.log("parse file: " + filename);
   	       parsedFiles.push(parsedFile);
   		   parsedFilenames.push(filename);
  	    }
    } // for
}

/**
 * Main
 *
 * @return {Number} Count parsed files.
 */
function main(defaults)
{
	// bin-parameters
	if(defaults) options = _.defaults(defaults, options);

	// marked (markdown) Settings.
	markdown.setOptions(options.marked);

	// Paths
	options.dest     = path.join(options.dest, "./");
	options.template = path.join(options.template, "./");

	// Funktionen erweitern / ersetzen
	_.defaults(options.logger, app.logger);
	_.defaults(options.filters, app.filters);
	_.defaults(options.parsers, app.parsers);
	_.defaults(options.workers, app.workers);

	var parser = new Parser(app);
	var parsedFiles = [];
	var parsedFilenames = [];
	var worker = new Worker(app);
	var filter = new Filter(app);

	try
	{
		// If input option for source is an array of folders,
		// parse each folder in the order provided.
		if (options.src instanceof Array)
		{
			options.src.forEach(function(folder)
			{
			   // Keep same options for each folder, but ensure the "src" of options
			   // is the folder currently being processed.
			   var folderOptions = options;
			   folderOptions.src = path.join(folder, "./");
			   parseFiles(parser, folderOptions, parsedFiles, parsedFilenames);
		    });
		 }
		 else
		 {
		 	// If the input option for source is a single folder, parse as usual.
		 	options.src = path.join(options.src, "./");
            parseFiles(parser, options, parsedFiles, parsedFilenames);
		 }

		// Worker / Filter
		if(parsedFiles.length > 0)
		{
			worker.process(parsedFiles, parsedFilenames);
			filter.process(parsedFiles, parsedFilenames);

			var packageInfos = getPackageData();
			createOutputFiles(parsedFiles, parsedFilenames, packageInfos);

			return parsedFiles.length;
		}
		else
		{
			app.log("Nothing to do.");
			return 0;
		}
	}
	catch(e)
	{
		if(e.stack) app.debug(e.stack);
		app.log(e);
	}
	return;
} // main

/**
 * Exports
 */
module.exports = main;

// Direct call
if(path.dirname(process.argv[1]) === __dirname) main();
<|endoftext|>


<commit_before>'use strict';

var Mocha = require('mocha');
var CustomRunner = require('./runner');
var queue = require('./queue');
var debug = require('debug')('mocha-parallel-tests');
var events = require('events');

var customRunner = new CustomRunner;
var UserReporter;

var setUserReporter = function (reporter) {
    try {
        UserReporter = require('mocha/lib/reporters/' + reporter)
    } catch (evt) {
        try {
            UserReporter = require(reporter);
        } catch (evt) {
            // console.log('Please use existing reporter');
            return;
        }
    }

    UserReporter = new UserReporter(customRunner);
};

function MochaParallelTests(runner, options) {
    var Base = Mocha.reporters.Base;

    if (!UserReporter) {
        setUserReporter(options.reporterName || 'spec');
    }

    Base.call(this, runner);

    // array events
    var eventsNotEmited = [];

    // test done
    var isFinished = false;
    // test in process
    var isRunning = false;
    // all test data
    var isDataFull = false;
    // has suites flag
    var hasSuites = false;

    var isLast = (options.index === options.testsLength);

    // if queue is free and task not finished start queue
    if (!queue.inProcess() && !isFinished) {
        queue.start();
        customRunner.start();
        isRunning = true;
    } else {
        // if queue is busy listen 'free' event
        queue.on('free', function () {
            // if task is not done and queue is free
            if (!isFinished && !queue.inProcess()) {
                // if all events in array and they don't include suites
                if (isDataFull && eventsNotEmited.length <= 2) {
                    queue.end();
                    return;
                }
                // if still in process of getting events
                if (!isDataFull) {
                    isRunning = true;
                }
                // start queue and emit events we already have
                queue.start();
                run();
            }
        });
    }

    // emit saved test events
    function run () {
        eventsNotEmited.forEach(function (eventData, type) {
            var key = Object.keys(eventData)[0];
            var isEndEvent = (key === 'end');
            var isStartEvent = (key === 'start');

            if (isStartEvent) return;

            if (isEndEvent && isLast) {
                customRunner.end();
                return;
            }

            try {
                customRunner[key](eventData[key]);
            } catch (evt) {}
        });
        // if all events saved finish test and exit queue
        if (isDataFull) {
            isFinished = true;
            queue.end();
        }
    }

    runner.on('suite', function(suite) {
        debug('suite');
        if (isRunning) {
            customRunner.suite(suite);
        } else {
            eventsNotEmited.push({suite: suite});
        }

        hasSuites = true;
    });

    runner.on('suite end', function(suite) {
        debug('suite end');
        if (isRunning) {
            customRunner.suiteEnd(suite);
        } else {
            eventsNotEmited.push({'suiteEnd': suite});
        }
    });

    runner.on('test', function(test) {
        debug('test');
        if (isRunning) {
            customRunner.test(test);
        } else {
            eventsNotEmited.push({'test': test});
        }
    });

    runner.on('pending', function(test) {
        debug('pending');
        if (isRunning) {
            customRunner.pending(test);
        } else {
            eventsNotEmited.push({'pending': test});
        }
    });

    runner.on('pass', function(test) {
        debug('pass');

        if (isRunning) {
            // it is not test file
            if (!hasSuites) {
                return;
            }
            customRunner.pass(test);
        } else {
            eventsNotEmited.push({'pass': test});
        }
    });

    runner.on('fail', function(test) {
        debug('fail');
        if (isRunning) {
            // it is not test file
            if (!hasSuites) {
                return;
            }
            try {
                customRunner.fail(arguments);
            } catch (evt) {}
        } else {
            eventsNotEmited.push({'fail': arguments});
        }
    });

    runner.on('test end', function(test) {
        debug('test end');
        if (isRunning) {
            customRunner.testEnd(test);
        } else {
            eventsNotEmited.push({'testEnd': test});
        }
    });

    runner.on('end', function() {
        debug('end');
        if (isRunning) {
            isFinished = true;
            isRunning = false;
            queue.end();
            if (isLast) {
                customRunner.end();
            }
        } else {
            eventsNotEmited.push({'end': {}});
            isDataFull = true;
        }
    });
}

module.exports = MochaParallelTests;<commit_msg>Fix end event for not tests<commit_after>'use strict';

var Mocha = require('mocha');
var CustomRunner = require('./runner');
var queue = require('./queue');
var debug = require('debug')('mocha-parallel-tests');
var events = require('events');

var customRunner = new CustomRunner;
var UserReporter;

var setUserReporter = function (reporter) {
    try {
        UserReporter = require('mocha/lib/reporters/' + reporter)
    } catch (evt) {
        try {
            UserReporter = require(reporter);
        } catch (evt) {
            // console.log('Please use existing reporter');
            return;
        }
    }

    UserReporter = new UserReporter(customRunner);
};

function MochaParallelTests(runner, options) {
    var Base = Mocha.reporters.Base;

    if (!UserReporter) {
        setUserReporter(options.reporterName || 'spec');
    }

    Base.call(this, runner);

    // array events
    var eventsNotEmited = [];

    // test done
    var isFinished = false;
    // test in process
    var isRunning = false;
    // all test data
    var isDataFull = false;
    // has suites flag
    var hasSuites = false;

    var isLast = (options.index === options.testsLength);

    // if queue is free and task not finished start queue
    if (!queue.inProcess() && !isFinished) {
        queue.start();
        customRunner.start();
        isRunning = true;
    } else {
        // if queue is busy listen 'free' event
        queue.on('free', function () {
            // if task is not done and queue is free
            if (!isFinished && !queue.inProcess()) {
                // if all events in array and they don't include suites
                if (isDataFull && eventsNotEmited.length <= 2) {
                    run();
                    queue.end();
                    return;
                }
                // if still in process of getting events
                if (!isDataFull) {
                    isRunning = true;
                }
                // start queue and emit events we already have
                queue.start();
                run();
            }
        });
    }

    // emit saved test events
    function run () {
        eventsNotEmited.forEach(function (eventData, type) {
            var key = Object.keys(eventData)[0];
            var isEndEvent = (key === 'end');
            var isStartEvent = (key === 'start');

            if (isStartEvent) return;

            if (isEndEvent && isLast) {
                customRunner.end();
                return;
            }

            try {
                customRunner[key](eventData[key]);
            } catch (evt) {}
        });
        // if all events saved finish test and exit queue
        if (isDataFull) {
            isFinished = true;
            queue.end();
        }
    }

    runner.on('suite', function(suite) {
        debug('suite');
        if (isRunning) {
            customRunner.suite(suite);
        } else {
            eventsNotEmited.push({suite: suite});
        }

        hasSuites = true;
    });

    runner.on('suite end', function(suite) {
        debug('suite end');
        if (isRunning) {
            customRunner.suiteEnd(suite);
        } else {
            eventsNotEmited.push({'suiteEnd': suite});
        }
    });

    runner.on('test', function(test) {
        debug('test');
        if (isRunning) {
            customRunner.test(test);
        } else {
            eventsNotEmited.push({'test': test});
        }
    });

    runner.on('pending', function(test) {
        debug('pending');
        if (isRunning) {
            customRunner.pending(test);
        } else {
            eventsNotEmited.push({'pending': test});
        }
    });

    runner.on('pass', function(test) {
        debug('pass');

        if (isRunning) {
            // it is not test file
            if (!hasSuites) {
                return;
            }
            customRunner.pass(test);
        } else {
            eventsNotEmited.push({'pass': test});
        }
    });

    runner.on('fail', function(test) {
        debug('fail');
        if (isRunning) {
            // it is not test file
            if (!hasSuites) {
                return;
            }
            try {
                customRunner.fail(arguments);
            } catch (evt) {}
        } else {
            eventsNotEmited.push({'fail': arguments});
        }
    });

    runner.on('test end', function(test) {
        debug('test end');
        if (isRunning) {
            customRunner.testEnd(test);
        } else {
            eventsNotEmited.push({'testEnd': test});
        }
    });

    runner.on('end', function() {
        debug('end');
        if (isRunning) {
            isFinished = true;
            isRunning = false;
            queue.end();
            if (isLast) {
                customRunner.end();
            }
        } else {
            eventsNotEmited.push({'end': {}});
            isDataFull = true;
        }
    });
}

module.exports = MochaParallelTests;<|endoftext|>


<commit_before>var express = require('express'),
    app = express(),
    server = require('http').Server(app),
    io = require('socket.io')(server),
    favicon = require('serve-favicon');
var ejs = require('ejs');
var mongoose = require('mongoose');
var async = require('async');

var setting = require("./setting.js");
var mainUI = require("./mainUI.js");
var DBModule = require("./DB_method/dbmodule.js");
var SendFiles = require("./SendFiles.js");
var color_settings = require("./color_settings.js");

var dbmodule = new DBModule(mongoose);

dbmodule.dbdefine();
dbmodule.tagdefine();
dbmodule.themedefine();

app.engine('ejs', ejs.renderFile);

mainUI.mainUI(app); //mainUIの情報を受け取る

app.use(favicon(__dirname + '/views/image/favicon.ico'));

io.sockets.on("connection", function(socket){
  socket.on('init_upload', function(cate_name){
    //positonの抽出
    dbmodule.dbposition_x_max(function(position_x){
      var x_max = position_x;
      dbmodule.dbposition_y_max(function(position_y_max){
        var y_max = position_y_max;
        dbmodule.dbposition_y_min(function(position_y_min){
          var y_min = position_y_min;
          socket.emit("position_limit", {
            "x_max": x_max,
            "y_max": y_max,
            "y_min": y_min
          });
        });
      });
    });

    //初回ページの要求
    dbmodule.dbcate(cate_name.category, function(init_data){  //normalカテゴリを表示
      //DBへtagデータの受け渡しの要求
      dbmodule.tagall(function(init_tag){
        for(var i = 0; i < init_tag.length; i++){
          init_tag[i].color = color_settings.color_settings[init_tag[i].color];
        }
        // 初期join
        socket.join(cate_name.category);

        socket.emit("init_update", {
          "data": init_data,
          "tag": init_tag
        });
      });
    });
  });

  //カテゴリチャンネルへの参加
  socket.on("request_category", function(cate_name){
    dbmodule.dbcate(cate_name.category, function(cate_data){  //カテゴリデータの抽出
      dbmodule.tagall(function(cate_tag){ //DBへのTagデータの受け渡し要求
        for(var i = 0; i < cate_tag.length; i++){
          if(cate_name.category != 'conversation'){
            cate_tag[i].color = color_settings.color_settings[cate_tag[i].color];
          }
          else{
            cate_tag[i].tag = null;
            cate_tag[i].color = null;
          }
        }
        dbmodule.themefind(0, function(find_theme){
          socket.join(cate_name.category); //カテゴリチャンネルに参加
          socket.emit("response_category", {
            "data": cate_data,
            "tag": cate_tag
          });
          if(cate_name.category == 'conversation'){
            socket.emit("conv_theme_response", {
              "theme": find_theme.theme,
              "_id": find_theme._id
            });
          }
        });
      });
    });
  });

  //語るカテゴリのテーマ登録
  socket.on("conv_theme_request",function(conv_theme){
    dbmodule.themecount(function(count){
      conv_theme._id = count; //counter数を投稿されたテーマのidとする
      dbmodule.themeinsert(conv_theme); //DBにテーマを登録
    });
  });

  //テーマの削除・変更
  socket.on("theme_choose",function(){
    dbmodule.themecount(function(themecount){
      var propcount = Math.floor(Math.random() * (themecount - 0) + 0); //投稿の総数を上限として数値を一つランダムで選ぶ
      //語るカテゴリにテーマが投稿されていればランダムに1つ抽出しsocketを送る
        dbmodule.themefind(propcount, function(choose_theme){
          io.sockets.emit("conv_theme_response",{
            "theme": choose_theme.theme,
            "_id": choose_theme._id
          });
          async.waterfall([
            function(callback){
              callback(null, 'one', 'two');
            },
            function(arg1, arg2, callback){ //先に全件削除を行う
              dbmodule.themeremove();
              callback(null, 'three');
            },
            function(arg1, callback){ //その後に_idを0にして追加
              dbmodule.themecount(function(count){
                choose_theme._id = count; //count数を投稿されたテーマのidとする
                callback(null, 'four');
              });
            },
            function(arg1, callback){
              dbmodule.themeinsert({
                "theme": choose_theme.theme,
                "_id": choose_theme._id
              });
              callback(null, 'done');
            }
          ]);
        });
    });
  });

  //tag情報の受け渡し
  socket.on('upload', function(upload){
    var propcount = Math.floor(Math.random() * (6 - 0) + 0);
    var count = 0;
    var update_tag = {};
    update_tag.tag = upload.data.tag;

    //新しいタグが投稿されたら
    if(upload.isnewtag){
      for (var result in color_settings.color_settings){
        if (propcount == count){
          update_tag.color = result;
          break;
        }
        count++;
      }
      dbmodule.taginsert({
        "tag": update_tag.tag,
        "color": update_tag.color
      });
    }
    else{
      dbmodule.tagfindone(update_tag.tag, function(doc){
        update_tag.color = doc.color;
      });
    }

    update_tag.color = color_settings.color_settings[update_tag.color];
    //upload.dataをDBに渡す
    dbmodule.dbinsert(upload.data);

    var NowCategory = upload.data.category;
    if(NowCategory == "conversation"){
      socket.to(upload.category).emit("update", {
        "data": upload.data
      });
    }
    else{
      socket.to(upload.category).emit("update", { //update.dataをフロントへ渡す
        "data": upload.data,
        "tag": update_tag
      });
    }
  });
});

SendFiles.send_Files(app);

server.listen(setting.port, setting.host, function(){
  console.log("server listening...  " + setting.host + ":" + setting.port);
});
<commit_msg>fix 'conversation'カテゴリ時のcolor検索バグ<commit_after>var express = require('express'),
    app = express(),
    server = require('http').Server(app),
    io = require('socket.io')(server),
    favicon = require('serve-favicon');
var ejs = require('ejs');
var mongoose = require('mongoose');
var async = require('async');

var setting = require("./setting.js");
var mainUI = require("./mainUI.js");
var DBModule = require("./DB_method/dbmodule.js");
var SendFiles = require("./SendFiles.js");
var color_settings = require("./color_settings.js");

var dbmodule = new DBModule(mongoose);

dbmodule.dbdefine();
dbmodule.tagdefine();
dbmodule.themedefine();

app.engine('ejs', ejs.renderFile);

mainUI.mainUI(app); //mainUIの情報を受け取る

app.use(favicon(__dirname + '/views/image/favicon.ico'));

io.sockets.on("connection", function(socket){
  socket.on('init_upload', function(cate_name){
    //positonの抽出
    dbmodule.dbposition_x_max(function(position_x){
      var x_max = position_x;
      dbmodule.dbposition_y_max(function(position_y_max){
        var y_max = position_y_max;
        dbmodule.dbposition_y_min(function(position_y_min){
          var y_min = position_y_min;
          socket.emit("position_limit", {
            "x_max": x_max,
            "y_max": y_max,
            "y_min": y_min
          });
        });
      });
    });

    //初回ページの要求
    dbmodule.dbcate(cate_name.category, function(init_data){  //normalカテゴリを表示
      //DBへtagデータの受け渡しの要求
      dbmodule.tagall(function(init_tag){
        for(var i = 0; i < init_tag.length; i++){
          init_tag[i].color = color_settings.color_settings[init_tag[i].color];
        }
        // 初期join
        socket.join(cate_name.category);

        socket.emit("init_update", {
          "data": init_data,
          "tag": init_tag
        });
      });
    });
  });

  //カテゴリチャンネルへの参加
  socket.on("request_category", function(cate_name){
    dbmodule.dbcate(cate_name.category, function(cate_data){  //カテゴリデータの抽出
      dbmodule.tagall(function(cate_tag){ //DBへのTagデータの受け渡し要求
        for(var i = 0; i < cate_tag.length; i++){
          if(cate_name.category != 'conversation'){
            cate_tag[i].color = color_settings.color_settings[cate_tag[i].color];
          }
          else{
            cate_tag[i].tag = null;
            cate_tag[i].color = null;
          }
        }
        dbmodule.themefind(0, function(find_theme){
          socket.join(cate_name.category); //カテゴリチャンネルに参加
          socket.emit("response_category", {
            "data": cate_data,
            "tag": cate_tag
          });
          if(cate_name.category == 'conversation'){
            socket.emit("conv_theme_response", {
              "theme": find_theme.theme,
              "_id": find_theme._id
            });
          }
        });
      });
    });
  });

  //語るカテゴリのテーマ登録
  socket.on("conv_theme_request",function(conv_theme){
    dbmodule.themecount(function(count){
      conv_theme._id = count; //counter数を投稿されたテーマのidとする
      dbmodule.themeinsert(conv_theme); //DBにテーマを登録
    });
  });

  //テーマの削除・変更
  socket.on("theme_choose",function(){
    dbmodule.themecount(function(themecount){
      var propcount = Math.floor(Math.random() * (themecount - 0) + 0); //投稿の総数を上限として数値を一つランダムで選ぶ
      //語るカテゴリにテーマが投稿されていればランダムに1つ抽出しsocketを送る
        dbmodule.themefind(propcount, function(choose_theme){
          io.sockets.emit("conv_theme_response",{
            "theme": choose_theme.theme,
            "_id": choose_theme._id
          });
          async.waterfall([
            function(callback){
              callback(null, 'one', 'two');
            },
            function(arg1, arg2, callback){ //先に全件削除を行う
              dbmodule.themeremove();
              callback(null, 'three');
            },
            function(arg1, callback){ //その後に_idを0にして追加
              dbmodule.themecount(function(count){
                choose_theme._id = count; //count数を投稿されたテーマのidとする
                callback(null, 'four');
              });
            },
            function(arg1, callback){
              dbmodule.themeinsert({
                "theme": choose_theme.theme,
                "_id": choose_theme._id
              });
              callback(null, 'done');
            }
          ]);
        });
    });
  });

  //tag情報の受け渡し
  socket.on('upload', function(upload){
    var propcount = Math.floor(Math.random() * (6 - 0) + 0);
    var count = 0;
    var update_tag = {};
    update_tag.tag = upload.data.tag;

    //新しいタグが投稿されたら
    if(upload.isnewtag){
      for (var result in color_settings.color_settings){
        if (propcount == count){
          update_tag.color = result;
          break;
        }
        count++;
      }
      dbmodule.taginsert({
        "tag": update_tag.tag,
        "color": update_tag.color
      });
    }
    else if(upload.data.category == 'normal'){
      dbmodule.tagfindone(update_tag.tag, function(doc){
        update_tag.color = doc.color;
      });
    }

    //upload.dataをDBに渡す
    dbmodule.dbinsert(upload.data);

    if(upload.data.category == "normal"){
      update_tag.color = color_settings.color_settings[update_tag.color];

      io.sockets.in(upload.data.category).emit("update", { //update.dataをフロントへ渡す
        "data": upload.data,
        "tag": update_tag
      });
    }
    else{
      io.sockets.in(upload.data.category).emit("update", {
        "data": upload.data
      });
    }
  });
});

SendFiles.send_Files(app);

server.listen(setting.port, setting.host, function(){
  console.log("server listening...  " + setting.host + ":" + setting.port);
});
<|endoftext|>


<commit_before>phoxy.render =
{
  DeferRender : function (ejs, data, rendered_callback, tag)
    {
      phoxy.Log(4, "phoxy.DeferRender", arguments);
      if (tag === undefined)
        tag = '<defer_render>';
      var canvas = phoxy._.render.PrepareCanvas(tag);
      var id = canvas.id;

      phoxy._.render.RenderReplace(id, ejs, data, rendered_callback);

      if (tag === null)
        return canvas;
      return canvas.html;
    }
  ,
};

phoxy._.render =
{
  PrepareCanvas : function(tag)
    {
      if (tag === undefined)
        tag = '<div>';
      var vanilla_tag = tag.substring(1, tag.length - 1);

      var id =  phoxy._.internal.GenerateUniqueID();
      var obj = document.createElement(vanilla_tag);
      obj.setAttribute('id', id);
      var div = obj.outerHTML;

      return { id: id, obj: obj, html: div };
    }
  ,
  AsyncRender_Strategy : function (target, ejs, data, rendered_callback, difference)
    { // AsyncRender strategy: for production
      phoxy._.render.Fancy(ejs, data, function async_strategy_birth(obj, ejs, data)
      {
        if (typeof obj === 'undefined')
        {
          phoxy.Log(3, 'phoxy.Reality', 'Design render skiped. (No design was choosed?)', document.getElementById(target));
          return; // And break dependencies execution
        }

        // Potential cascade memleak
        // Should clear listeners with callback
        phoxy._.time.Appeared(target, function async_strategy_wait_for_apperance()
        {
          difference.call(phoxy, target, obj.html, arguments);
          for (var k in obj.defer)
              obj.defer[k]();
        }, undefined, -1);

        obj.on_complete = function async_strategy_on_complete()
        {
          if (typeof(rendered_callback) !== 'undefined')
            rendered_callback.call(obj.across, ejs, data, obj.html);
        };
      }, true);
    }
  ,
  SyncRender_Strategy : function (target, ejs, data, rendered_callback, difference)
    { // SyncRender strategy: for debug/develop purposes
      phoxy._.time.Appeared(target, function sync_strategy_wait_for_apperance()
      {
        phoxy._.render.Fancy(ejs, data, function sync_strategy_birth(obj, ejs, data)
        {
          if (typeof obj === 'undefined')
          {
            phoxy.Log(3, 'phoxy.Reality', 'Design render skiped. (No design was choosed?)', document.getElementById(target));
            return; // And break dependencies execution
          }

          difference.call(phoxy, target, obj.html, arguments);

          obj.on_complete = function sync_strategy_on_complete()
          {
            if (typeof(rendered_callback) !== 'undefined')
              rendered_callback.call(obj.across, ejs, data, obj.html);
          };
        }, true);
      }, undefined, -1);
    }
  ,
  RenderStrategy : "Will be replaced by selected strategy after compilation."
  ,
  RenderInto : function (target, ejs, data, rendered_callback)
    {
      var args = Array.prototype.slice.call(arguments);
      args.push(function render_into_f(target, html)
      {
        document.getElementById(target).innerHTMl = html;
      });
      phoxy._.render.RenderStrategy.apply(this, args);
    }
  ,
  RenderReplace : function (target, ejs, data, rendered_callback)
    {
      var args = Array.prototype.slice.call(arguments);
      args.push(function render_replace_f(target, html)
      {
        var that = document.getElementById(target);
        that.insertAdjacentHTML("afterEnd", html);
        that.parentNode.removeChild(that);
      });
      phoxy._.render.RenderStrategy.apply(this, args);
    }
  ,
  Render : function (design, data, callback, is_phoxy_internal_call)
    {
      phoxy.Log(2, "phoxy.Render is OBSOLETE. Use phoxy.Fancy instead");

      if (data === undefined)
        data = {};

      var html;
      if (design.indexOf(".ejs") === -1)
        design += ".ejs";
      var ejs;
      //if (!phoxy.ForwardDownload(design))
        ejs = new EJS({'url' : design});
      //else
//        ejs = new EJS({'text' : phoxy.ForwardDownload(design), 'name' : design});

      var obj = ejs.prepare(data);
      obj.on_complete = callback;
      ejs.execute(obj);
      html = obj.html;

      if (typeof phoxy === 'undefined' || typeof phoxy.state === 'undefined')
        throw "EJS render failed. Phoxy is missing. Is .ejs file exsists? Is your .htacess right? Check last AJAX request.";

      if (is_phoxy_internal_call)
        return obj;
      return html;
    }
  ,
  Fancy : function()
    {
      var args = arguments;
      for (var i = 0; i < 2; i++)
        if (Array.isArray(args[i]))
        {
          args[i] = phoxy.ConstructURL(args[i]);
          return phoxy._.render.Fancy.apply(this, args);
        }

      phoxy.Log(6, "phoxy.Fancy", arguments);

      var callback = args[2];
      if (typeof(callback) === 'undefined')
        callback = function (){};

      return new phoxy._.birth(args[0], args[1], callback, true);
    }
  ,
};

phoxy._.birth = function(will, spirit, callback, raw_output)
{
  this.will = will;
  this.spirit = spirit;
  this.birth_id = phoxy._.internal.GenerateUniqueID();
  console.time("phoxy.birth " + this.birth_id);
  this.callback = function birth_log_report()
  {
    console.groupCollapsed("phoxy.birth", will);
      console.log(spirit);
      for (var k in this.log)
        console.log.apply(console, this.log[k]);

    console.timeEnd("phoxy.birth " + this.birth_id);
    console.groupEnd();

    callback.apply(this, arguments);
  }
  this.raw_output = raw_output;
  this.log = [];

  return this.Decision(will, spirit, callback);
}

phoxy._.birth.prototype =
{
  Decision: function(will, spirit)
    {
      this.Log("Decision", arguments);
      if (typeof spirit === 'undefined')
        return this.Fortune(will);
      if (typeof spirit !== 'object')
        return this.Hope(will, spirit);
      return this.Fate(will, spirit);
    }
  ,
  Fortune: function(word)
    {
      this.Log("Fortune", arguments);
      if (typeof(word) === 'undefined')
        return this.Vision();
      else if (typeof(word) === 'string')
        return this.Prophecy(word);
      else if (typeof(word) !== 'object')
        return this.Presage(word);
      phoxy.Log(0, "birth.Fortune", word, "(Failed object recognize)");
    }
  ,
  Hope: function()
    {
      this.Log("Hope", arguments);
      var args = arguments;
      var idea = args[1];

      function DataLoadedCallback(data)
      {
        data = data || {};
        this.Decision(args[0], data, args[2], args[3]);
      }

      if (typeof(idea) === 'string')
        return this.Desire(idea, DataLoadedCallback);
      else if (typeof(idea) === 'function')
      {
        var data = this.Pray(args[1], DataLoadedCallback);
        if (typeof(data) === 'object')
          DataLoadedCallback(data);
      }
      else
        phoxy.Log(0, "birth.Hope", idea, "(Failed data receive)");
    }
  ,
  Fate: function(design, data)
    {
      this.Log("Fate", arguments);
      if (typeof(design) === 'undefined')
        return this.Vision(design, data);
      else if (typeof(design) === 'function')
        design = this.Mutation.apply(this, arguments);

      if (typeof(design) === 'string')
        return this.Conceive(design, data);
    }
  ,
  Vision: function(cb, design, data)
    {
      this.Log("Vision", arguments);
      return cb(design, data);
    }
  ,
  Prophecy: function(rpc)
    {
      this.Log("Prophecy", arguments);
      this.Plea(rpc, function on_rpc_design_received(obj)
      {
        this.Presage(obj);
      });
    }
  ,
  Presage: function(obj)
    {
      this.Log("Presage", arguments);

      // Maybe its wrong. Maybe i should ignore other params
      var design = obj.design;
      var data = obj.data || {};

      this.Boon(obj, function on_design_object_decoded()
      {
        this.Decision(design, data, this.callback);
      })
    }
  ,
  Pray: function(data_load_functor, DataLoadedCallback)
    {
      this.Log("Pray", arguments);
      return data_load_functor(DataLoadedCallback);
    }
  ,
  Mutation: function(design, data)
    {
      this.Log("Mutation", arguments);
      function DetermineAsync(design)
      {
        phoxy._.render.Fancy(design, data, args[2], args[3]);
      }

      return design(data, DetermineAsync);
    }
  ,
  Conceive: function(design, data)
    {
      this.Log("Conceive", arguments);
      var ejs_location = phoxy.Config()['ejs_dir'] + "/" + design;
      var html = this.Render(ejs_location, data);

      if (!this.raw_output)
        html = html.html;
      this.callback(html, design, data);
    }
  ,
  Desire: function(rpc, DataLoadedCallback)
    {
      this.Log("Desire", arguments);
      this.Plea(rpc, function on_data_recieved(json)
      {
        DataLoadedCallback(json.data);
      });
    }
  ,
  Plea: function(url, cb)
    {
      this.Log("Plea", arguments);
      var that = this;
      phoxy.AJAX(url, function on_ajax_answer(obj)
      {
        that.Boon(obj, cb);
      });
    }
  ,
  Boon: function(answer, cb)
  {
    this.Log("Boon", arguments);
    var obj = EJS.IsolateContext(answer);

    // Those removed because we dont need to render anything
    delete obj.design;
    // Those ignored since it phoxy.Fancy.(low level rendering) Place to render already choosed
    delete obj.result;
    delete obj.replace;
    var that = this;
    phoxy.ApiAnswer(obj, function on_default_action_done()
    {
      cb.call(that, answer);
    });
  }
  ,
  Log: function()
    {
      this.log.push(arguments);
    }
  ,
  Render: function(design, data)
  {
    var html;
    if (design.indexOf(".ejs") === -1)
        design += ".ejs";

    var ejs;
    //if (!phoxy.ForwardDownload(design))
      ejs = new EJS({'url' : design});
    //else
    // ejs = new EJS({'text' : phoxy.ForwardDownload(design), 'name' : design});

    var that = this;
    function log()
    {
      that.Log.apply(that, arguments);
    }

    var obj = ejs.prepare(data);
      obj.on_complete = this.callback;
      obj.log = log;
      ejs.execute(obj);

    return obj;
  }
}<commit_msg>Async birth render<commit_after>phoxy.render =
{
  DeferRender : function (ejs, data, rendered_callback, tag)
    {
      phoxy.Log(4, "phoxy.DeferRender", arguments);
      if (tag === undefined)
        tag = '<defer_render>';
      var canvas = phoxy._.render.PrepareCanvas(tag);
      var id = canvas.id;

      phoxy._.render.RenderReplace(id, ejs, data, rendered_callback);

      if (tag === null)
        return canvas;
      return canvas.html;
    }
  ,
};

phoxy._.render =
{
  PrepareCanvas : function(tag)
    {
      if (tag === undefined)
        tag = '<div>';
      var vanilla_tag = tag.substring(1, tag.length - 1);

      var id =  phoxy._.internal.GenerateUniqueID();
      var obj = document.createElement(vanilla_tag);
      obj.setAttribute('id', id);
      var div = obj.outerHTML;

      return { id: id, obj: obj, html: div };
    }
  ,
  AsyncRender_Strategy : function (target, ejs, data, rendered_callback, difference)
    { // AsyncRender strategy: for production
      phoxy._.render.Fancy(ejs, data, function async_strategy_birth(obj, ejs, data)
      {
        if (typeof obj === 'undefined')
        {
          phoxy.Log(3, 'phoxy.Reality', 'Design render skiped. (No design was choosed?)', document.getElementById(target));
          return; // And break dependencies execution
        }

        // Potential cascade memleak
        // Should clear listeners with callback
        phoxy._.time.Appeared(target, function async_strategy_wait_for_apperance()
        {
          difference.call(phoxy, target, obj.html, arguments);
          for (var k in obj.defer)
              obj.defer[k]();
        }, undefined, -1);

        obj.on_complete = function async_strategy_on_complete()
        {
          if (typeof(rendered_callback) !== 'undefined')
            rendered_callback.call(obj.across, ejs, data, obj.html);
        };
      }, true);
    }
  ,
  SyncRender_Strategy : function (target, ejs, data, rendered_callback, difference)
    { // SyncRender strategy: for debug/develop purposes
      phoxy._.time.Appeared(target, function sync_strategy_wait_for_apperance()
      {
        phoxy._.render.Fancy(ejs, data, function sync_strategy_birth(obj, ejs, data)
        {
          if (typeof obj === 'undefined')
          {
            phoxy.Log(3, 'phoxy.Reality', 'Design render skiped. (No design was choosed?)', document.getElementById(target));
            return; // And break dependencies execution
          }

          difference.call(phoxy, target, obj.html, arguments);

          obj.on_complete = function sync_strategy_on_complete()
          {
            if (typeof(rendered_callback) !== 'undefined')
              rendered_callback.call(obj.across, ejs, data, obj.html);
          };
        }, true);
      }, undefined, -1);
    }
  ,
  RenderStrategy : "Will be replaced by selected strategy after compilation."
  ,
  RenderInto : function (target, ejs, data, rendered_callback)
    {
      var args = Array.prototype.slice.call(arguments);
      args.push(function render_into_f(target, html)
      {
        document.getElementById(target).innerHTMl = html;
      });
      phoxy._.render.RenderStrategy.apply(this, args);
    }
  ,
  RenderReplace : function (target, ejs, data, rendered_callback)
    {
      var args = Array.prototype.slice.call(arguments);
      args.push(function render_replace_f(target, html)
      {
        var that = document.getElementById(target);
        that.insertAdjacentHTML("afterEnd", html);
        that.parentNode.removeChild(that);
      });
      phoxy._.render.RenderStrategy.apply(this, args);
    }
  ,
  Render : function (design, data, callback, is_phoxy_internal_call)
    {
      phoxy.Log(2, "phoxy.Render is OBSOLETE. Use phoxy.Fancy instead");

      if (data === undefined)
        data = {};

      var html;
      if (design.indexOf(".ejs") === -1)
        design += ".ejs";
      var ejs;
      //if (!phoxy.ForwardDownload(design))
        ejs = new EJS({'url' : design});
      //else
//        ejs = new EJS({'text' : phoxy.ForwardDownload(design), 'name' : design});

      var obj = ejs.prepare(data);
      obj.on_complete = callback;
      ejs.execute(obj);
      html = obj.html;

      if (typeof phoxy === 'undefined' || typeof phoxy.state === 'undefined')
        throw "EJS render failed. Phoxy is missing. Is .ejs file exsists? Is your .htacess right? Check last AJAX request.";

      if (is_phoxy_internal_call)
        return obj;
      return html;
    }
  ,
  Fancy : function()
    {
      var args = arguments;
      for (var i = 0; i < 2; i++)
        if (Array.isArray(args[i]))
        {
          args[i] = phoxy.ConstructURL(args[i]);
          return phoxy._.render.Fancy.apply(this, args);
        }

      phoxy.Log(6, "phoxy.Fancy", arguments);

      var callback = args[2];
      if (typeof(callback) === 'undefined')
        callback = function (){};

      return new phoxy._.birth(args[0], args[1], callback, true);
    }
  ,
};

phoxy._.birth = function(will, spirit, callback, raw_output)
{
  this.will = will;
  this.spirit = spirit;
  this.birth_id = phoxy._.internal.GenerateUniqueID();
  console.time("phoxy.birth " + this.birth_id);
  this.callback = function birth_log_report()
  {
    console.groupCollapsed("phoxy.birth", will);
      console.log(spirit);
      for (var k in this.log)
        console.log.apply(console, this.log[k]);

    console.timeEnd("phoxy.birth " + this.birth_id);
    console.groupEnd();

    callback.apply(this, arguments);
  }
  this.raw_output = raw_output;
  this.log = [];

  return this.Decision(will, spirit, callback);
}

phoxy._.birth.prototype =
{
  Decision: function(will, spirit)
    {
      this.Log("Decision", arguments);
      if (typeof spirit === 'undefined')
        return this.Fortune(will);
      if (typeof spirit !== 'object')
        return this.Hope(will, spirit);
      return this.Fate(will, spirit);
    }
  ,
  Fortune: function(word)
    {
      this.Log("Fortune", arguments);
      if (typeof(word) === 'undefined')
        return this.Vision();
      else if (typeof(word) === 'string')
        return this.Prophecy(word);
      else if (typeof(word) !== 'object')
        return this.Presage(word);
      phoxy.Log(0, "birth.Fortune", word, "(Failed object recognize)");
    }
  ,
  Hope: function()
    {
      this.Log("Hope", arguments);
      var args = arguments;
      var idea = args[1];

      function DataLoadedCallback(data)
      {
        data = data || {};
        this.Decision(args[0], data, args[2], args[3]);
      }

      if (typeof(idea) === 'string')
        return this.Desire(idea, DataLoadedCallback);
      else if (typeof(idea) === 'function')
      {
        var data = this.Pray(args[1], DataLoadedCallback);
        if (typeof(data) === 'object')
          DataLoadedCallback(data);
      }
      else
        phoxy.Log(0, "birth.Hope", idea, "(Failed data receive)");
    }
  ,
  Fate: function(design, data)
    {
      this.Log("Fate", arguments);
      if (typeof(design) === 'undefined')
        return this.Vision(design, data);
      else if (typeof(design) === 'function')
        design = this.Mutation.apply(this, arguments);

      if (typeof(design) === 'string')
        return this.Conceive(design, data);
    }
  ,
  Vision: function(cb, design, data)
    {
      this.Log("Vision", arguments);
      return cb(design, data);
    }
  ,
  Prophecy: function(rpc)
    {
      this.Log("Prophecy", arguments);
      this.Plea(rpc, function on_rpc_design_received(obj)
      {
        this.Presage(obj);
      });
    }
  ,
  Presage: function(obj)
    {
      this.Log("Presage", arguments);

      // Maybe its wrong. Maybe i should ignore other params
      var design = obj.design;
      var data = obj.data || {};

      this.Boon(obj, function on_design_object_decoded()
      {
        this.Decision(design, data, this.callback);
      })
    }
  ,
  Pray: function(data_load_functor, DataLoadedCallback)
    {
      this.Log("Pray", arguments);
      return data_load_functor(DataLoadedCallback);
    }
  ,
  Mutation: function(design, data)
    {
      this.Log("Mutation", arguments);
      function DetermineAsync(design)
      {
        phoxy._.render.Fancy(design, data, args[2], args[3]);
      }

      return design(data, DetermineAsync);
    }
  ,
  Conceive: function(design, data)
    {
      this.Log("Conceive", arguments);
      var ejs_location = phoxy.Config()['ejs_dir'] + "/" + design;
      var html = this.Render(ejs_location, data);

      if (!this.raw_output)
        html = html.html;
      this.callback(html, design, data);
    }
  ,
  Desire: function(rpc, DataLoadedCallback)
    {
      this.Log("Desire", arguments);
      this.Plea(rpc, function on_data_recieved(json)
      {
        DataLoadedCallback(json.data);
      });
    }
  ,
  Plea: function(url, cb)
    {
      this.Log("Plea", arguments);
      var that = this;
      phoxy.AJAX(url, function on_ajax_answer(obj)
      {
        that.Boon(obj, cb);
      });
    }
  ,
  Boon: function(answer, cb)
  {
    this.Log("Boon", arguments);
    var obj = EJS.IsolateContext(answer);

    // Those removed because we dont need to render anything
    delete obj.design;
    // Those ignored since it phoxy.Fancy.(low level rendering) Place to render already choosed
    delete obj.result;
    delete obj.replace;
    var that = this;
    phoxy.ApiAnswer(obj, function on_default_action_done()
    {
      cb.call(that, answer);
    });
  }
  ,
  Log: function()
    {
      this.log.push(arguments);
    }
  ,
  Render: function(design, data, cb)
  {
    var async = typeof cb === 'function';

    if (design.indexOf(".ejs") === -1)
        design += ".ejs";

    var ejs = new EJS({'url' : design}, async ? WhenReady : undefined);

    var that = this;
    function WhenReady()
    {
      function log()
      {
        that.Log.apply(that, arguments);
      }

      var obj = ejs.prepare(data);

      obj.on_complete = this.callback;
      obj.log = log;
      ejs.execute(obj);

      if (async)
        cb(obj);

      return obj;
    }

    if (!async)
      return WhenReady();
  }
}<|endoftext|>


<commit_before>const MongoClient = require("mongodb").MongoClient;
const moment = require("moment");
const async = require("async");

const mongodbUrl = "mongodb://localhost:27017/npm";

// CALC PACKAGE TREND
var calcPackageTrend = function(id, done) {
	global.downloadsCol
		.find(
			{
				"_id.pkg": id,
				"_id.date": {
					$lte: moment()
						.utc()
						.subtract(31, "days")
						.startOf("day")
						.toDate()
				}
			},
			{ sort: [["_id.date", 1]] }
		)
		.toArray((err, downloads_daysago) => {
			// download history available

			var present = downloads_daysago[0].dl;
			var past = downloads_daysago[downloads_daysago.length - 1].dl;

			var growth =
				Math.pow(present / past, 1 / downloads_daysago.length) - 1;

			console.log(id, growth);

			global.packagesCol.updateOne(
				{
					_id: id
				},
				{
					$set: {
						trend: growth
					}
				},
				(err, results) => {
					console.log(err, results);
					return done(err, results);
				}
			);
		});
};

// open mongodb connection
MongoClient.connect(mongodbUrl, (err, db) => {
	// init collections
	global.downloadsCol = db.collection("downloads");
	global.packagesCol = db.collection("packages");

	global.packagesCol
		.find(
			{},
			{
				_id: true
			}
		)
		.toArray((err, pkgs) => {
			async.each(
				pkgs,
				(p, done) => {
					calcPackageTrend(p._id, done);
				},
				() => {
					console.log("Trends done!");
				}
			);
		});
});
<commit_msg>no message<commit_after>const MongoClient = require("mongodb").MongoClient;
const moment = require("moment");
const async = require("async");

const mongodbUrl = "mongodb://localhost:27017/npm";

// CALC PACKAGE TREND
var calcPackageTrend = function(id, done) {
	global.downloadsCol
		.find(
			{
				"_id.pkg": id,
				"_id.date": {
					$lte: moment()
						.utc()
						.subtract(31, "days")
						.startOf("day")
						.toDate()
				}
			},
			{ sort: [["_id.date", 1]] }
		)
		.toArray((err, downloads_daysago) => {
			// download history available
			var present = downloads_daysago[0].dl;
			var past = downloads_daysago[downloads_daysago.length - 1].dl;

			var growth =
				Math.pow(present / past, 1 / downloads_daysago.length) - 1;

			console.log(id, growth);

			global.packagesCol.updateOne(
				{
					_id: id
				},
				{
					$set: {
						trend: parseFloat(growth)
					}
				},
				{ upsert: true },
				(err, results) => {
					console.log(err, results);
					return done(err, results);
				}
			);
		});
};

// open mongodb connection
MongoClient.connect(mongodbUrl, (err, db) => {
	// init collections
	global.downloadsCol = db.collection("downloads");
	global.packagesCol = db.collection("packages");

	global.packagesCol
		.find(
			{},
			{
				_id: true
			}
		)
		.toArray((err, pkgs) => {
			async.each(
				pkgs,
				(p, done) => {
					calcPackageTrend(p._id, done);
				},
				() => {
					console.log("Trends done!");
				}
			);
		});
});
<|endoftext|>