<commit_before>// Karma configuration

const commonjs = require('rollup-plugin-commonjs');
// const angular = require('rollup-plugin-angular');
const nodeResolve = require('rollup-plugin-node-resolve');
const typescript = require('rollup-plugin-typescript');

module.exports = function(config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jasmine'],

    // list of files / patterns to load in the browser
    files: [
      'test/index.ts',
      'test/*.ts'
    ],

    plugins: [
      require('karma-coverage'),
      require('karma-chrome-launcher'),
      require('karma-rollup-preprocessor'),
      require('karma-jasmine')
    ],

    // list of files to exclude
    exclude: [],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
      'test/index.ts': ['rollup'],
      'test/*.ts': ['rollup'],
      'test/*.js': ['rollup'],
    },

    rollupPreprocessor: {
      context: 'this',
      // will help to prevent conflicts between different tests entries
      moduleName: 'ngxprismcore',
      format: 'iife',
      sourceMap: 'inline',
      // rollup settings. See Rollup documentation
      plugins: [
        // angular(),
        commonjs(),
        nodeResolve({
          // use "es2015" field for ES2015 modules with ES2015 code,
          // if possible
          es2015: true, // Default: false

          // use "module" field for ES2015 modules with ES5 code,
          // if possible
          module: true, // Default: true

          // use "jsnext:main" if possible
          // – see https://github.com/rollup/rollup/wiki/jsnext:main
          jsnext: true,  // Default: false

          // use "main" field or index.js, even if it's not an ES6 module
          // (needs to be converted from CommonJS to ES6
          // – see https://github.com/rollup/rollup-plugin-commonjs
          main: true,  // Default: true

          extensions: [ '.js', '.json' ]
        }),
        typescript({
          typescript: require('./node_modules/typescript')
        }),
      ],
    },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['progress'],

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    mime: {
      'text/x-typescript': ['ts','tsx']
    },

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['Chrome'],

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false,

    // Concurrency level
    // how many browser should be started simultaneous
    concurrency: Infinity
  })
}
<commit_msg>chore(karma.config): remove preprocessor *.js<commit_after>// Karma configuration

const commonjs = require('rollup-plugin-commonjs');
// const angular = require('rollup-plugin-angular');
const nodeResolve = require('rollup-plugin-node-resolve');
const typescript = require('rollup-plugin-typescript');

module.exports = function(config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jasmine'],

    // list of files / patterns to load in the browser
    files: [
      'test/index.ts',
      'test/*.ts'
    ],

    plugins: [
      require('karma-coverage'),
      require('karma-chrome-launcher'),
      require('karma-rollup-preprocessor'),
      require('karma-jasmine')
    ],

    // list of files to exclude
    exclude: [],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
      'test/index.ts': ['rollup'],
      'test/*.ts': ['rollup']
    },

    rollupPreprocessor: {
      context: 'this',
      // will help to prevent conflicts between different tests entries
      moduleName: 'ngxprismcore',
      format: 'iife',
      sourceMap: 'inline',
      // rollup settings. See Rollup documentation
      plugins: [
        // angular(),
        commonjs(),
        nodeResolve({
          // use "es2015" field for ES2015 modules with ES2015 code,
          // if possible
          es2015: true, // Default: false

          // use "module" field for ES2015 modules with ES5 code,
          // if possible
          module: true, // Default: true

          // use "jsnext:main" if possible
          // – see https://github.com/rollup/rollup/wiki/jsnext:main
          jsnext: true,  // Default: false

          // use "main" field or index.js, even if it's not an ES6 module
          // (needs to be converted from CommonJS to ES6
          // – see https://github.com/rollup/rollup-plugin-commonjs
          main: true,  // Default: true

          extensions: [ '.js', '.json' ]
        }),
        typescript({
          typescript: require('./node_modules/typescript')
        }),
      ],
    },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['progress'],

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    mime: {
      'text/x-typescript': ['ts','tsx']
    },

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['Chrome'],

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false,

    // Concurrency level
    // how many browser should be started simultaneous
    concurrency: Infinity
  })
}
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var should = require('should');
var gutil = require('gulp-util');
var testsuite = require('../testsuite');
var del = require('del');
var exec = require('child_process').exec;
require('shelljs/global');

module.exports = function(hg) {

    var cloneDestinationPath = testsuite.repoTestFolders[1];
    var cwd = process.cwd();

    beforeEach(function(done) {
        hg.clone(testsuite.remoteRepository, cloneDestinationPath, {args: '--insecure'}, function(err) {
            should(err).not.exists;
            cd(cloneDestinationPath);
            done();
        });

    });

    it('should have cloned project into a specific directory', function() {
        hg.utils.isHg().should.be.equal(true);
    });

    afterEach(function() {
        cd(cwd);
    });
};
<commit_msg>Included update.spec.js in clone.spec.js<commit_after>'use strict';

var fs = require('fs');
var should = require('should');
var gutil = require('gulp-util');
var testsuite = require('../testsuite');
var del = require('del');
var exec = require('child_process').exec;
require('shelljs/global');

module.exports = function(hg) {

    var cloneDestinationPath = testsuite.repoTestFolders[1];
    var cwd = process.cwd();

    beforeEach(function(done) {
        hg.clone(testsuite.remoteRepository, cloneDestinationPath, function(err) {
            should(err).not.exists;
            done();
        });

    });

    it('should have cloned project into a specific directory', function(done) {
        cd(cloneDestinationPath);
        hg.utils.isHg().should.be.equal(true);
        done();
    });

    afterEach(function() {
        cd(cwd);
    });
};
<|endoftext|>


<commit_before>/**
 * Copyright (C) 2020 3D Repo Ltd
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 */

const { config } = require('../lib/config');
const { generateAssetBundles, validateUnityConfigurations } = require('../tasks/unityEditor');
const { ERRCODE_ARG_FILE_FAIL, ERRCODE_BUNDLE_GEN_FAIL } = require('../constants/errorCodes');
const { UNITY_PROCESSING } = require('../constants/errorCodes');
const logger = require('../lib/logger');

const logLabel = { label: 'UNITYQ' };

const processUnity = async (database, model, logDir, modelImportErrCode) => {
	const returnMessage = {
		value: modelImportErrCode,
		database,
		project: model,
	};

	try {
		if (database && model) {
			await generateAssetBundles(database, model, logDir);
		} else {
			returnMessage.value = ERRCODE_ARG_FILE_FAIL;
		}
	} catch (err) {
		logger.error(`Failed to generate asset bundle: ${err.message || err}`, logLabel);
		returnMessage.value = ERRCODE_BUNDLE_GEN_FAIL;
	}

	return returnMessage;
};

const Handler = {};

Handler.onMessageReceived = async (cmd, rid, callback) => {
	const { database, project, value } = JSON.parse(cmd);
	const logDir = `${config.logging.taskLogDir}/${rid.toString()}/`;

	callback(JSON.stringify({
		status: UNITY_PROCESSING,
		database,
		project,
	}));

	const message = await processUnity(database, project, logDir, value);
	callback(JSON.stringify(message));
};

Handler.validateConfiguration = () => {
	if (!(config.rabbitmq && config.rabbitmq.callback_queue)) {
		logger.error('rabbitmq.callback_queue is not specified!', logLabel);
		return false;
	}

	if (!config.rabbitmq.unity_queue) {
		logger.error('rabbitmq.unity_queue is not specified!', logLabel);
		return false;
	}

	if (!(config.logging && config.logging.taskLogDir)) {
		logger.error('config.logging.taskLogDir is not specified!', logLabel);
		return false;
	}

	return validateUnityConfigurations();
};

module.exports = Handler;
<commit_msg>ISSUE #366 fix import<commit_after>/**
 * Copyright (C) 2020 3D Repo Ltd
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 */

const { config } = require('../lib/config');
const { generateAssetBundles, validateUnityConfigurations } = require('../tasks/unityEditor');
const { ERRCODE_ARG_FILE_FAIL, ERRCODE_BUNDLE_GEN_FAIL } = require('../constants/errorCodes');
const { UNITY_PROCESSING } = require('../constants/statuses');
const logger = require('../lib/logger');

const logLabel = { label: 'UNITYQ' };

const processUnity = async (database, model, logDir, modelImportErrCode) => {
	const returnMessage = {
		value: modelImportErrCode,
		database,
		project: model,
	};

	try {
		if (database && model) {
			await generateAssetBundles(database, model, logDir);
		} else {
			returnMessage.value = ERRCODE_ARG_FILE_FAIL;
		}
	} catch (err) {
		logger.error(`Failed to generate asset bundle: ${err.message || err}`, logLabel);
		returnMessage.value = ERRCODE_BUNDLE_GEN_FAIL;
	}

	return returnMessage;
};

const Handler = {};

Handler.onMessageReceived = async (cmd, rid, callback) => {
	const { database, project, value } = JSON.parse(cmd);
	const logDir = `${config.logging.taskLogDir}/${rid.toString()}/`;

	callback(JSON.stringify({
		status: UNITY_PROCESSING,
		database,
		project,
	}));

	const message = await processUnity(database, project, logDir, value);
	callback(JSON.stringify(message));
};

Handler.validateConfiguration = () => {
	if (!(config.rabbitmq && config.rabbitmq.callback_queue)) {
		logger.error('rabbitmq.callback_queue is not specified!', logLabel);
		return false;
	}

	if (!config.rabbitmq.unity_queue) {
		logger.error('rabbitmq.unity_queue is not specified!', logLabel);
		return false;
	}

	if (!(config.logging && config.logging.taskLogDir)) {
		logger.error('config.logging.taskLogDir is not specified!', logLabel);
		return false;
	}

	return validateUnityConfigurations();
};

module.exports = Handler;
<|endoftext|>


<commit_before>import Orbit from 'orbit/main';
import Document from 'orbit/document';
import Transformable from 'orbit/transformable';
import Requestable from 'orbit/requestable';
import { assert } from 'orbit/lib/assert';
import { required } from 'orbit/lib/stubs';
import { Class, expose, isArray, isObject, isNone } from 'orbit/lib/objects';
import Cache from './cache';
import Operation from 'orbit/operation';
import { LinkNotFoundException } from './lib/exceptions';

/**
 `Source` is an abstract base class to be extended by other sources.

 @class Source
 @namespace OC
 @param {OC.Schema} [schema]
 @param {Object}    [options]
 @param {Boolean}   [options.useCache] Should source use a cache?
 @param {Object}    [options.cacheOptions] Options for cache, if used.
 @constructor
*/
var Source = Class.extend({
  init: function(schema, options) {
    assert("Source's `schema` must be specified", schema);

    this.schema = schema;

    options = options || {};

    // Create an internal cache and expose some elements of its interface
    if (options.useCache) {
      this._cache = new Cache(schema, options.cacheOptions);
      expose(this, this._cache, 'length', 'reset', 'retrieve', 'retrieveLink');
    }

    Transformable.extend(this);
    Requestable.extend(this, ['find', 'add', 'update', 'patch', 'remove',
                              'findLink', 'addLink', 'removeLink', 'updateLink',
                              'findLinked']);

    Source.created(this);
  },

  /////////////////////////////////////////////////////////////////////////////
  // Transformable interface implementation
  /////////////////////////////////////////////////////////////////////////////

  /**
   Internal method that applies a single transform to this source.

   `_transform` must be implemented by a `Transformable` source.
   It is called by the public method `transform` in order to actually apply
   transforms.

   `_transform` should return a promise if the operation is asynchronous.

   @method _transform
   @param operation JSON PATCH operation as detailed in RFC 6902
   @private
   */
  _transform: required,

  /////////////////////////////////////////////////////////////////////////////
  // Requestable interface implementation
  /////////////////////////////////////////////////////////////////////////////

  _find: required,

  _findLink: required,

  _findLinked: function(type, id, link, options) {
    var modelId = this.getId(type, id);
    var linkType = this.schema.linkDefinition(type, link).model;
    var linkValue = this.retrieveLink(type, modelId, link);

    if (linkValue === undefined) throw new LinkNotFoundException(type, id, link);
    if (linkValue === null) return null;

    return this._find(linkType, linkValue, options);
  },

  _add: function(type, data) {
    data = data || {};

    var record = this.normalize(type, data);

    var id = this.getId(type, record),
        path = [type, id],
        _this = this;

    return this.transform(this.schema.operationEncoder.addRecordOp(type, id, record)).then(function() {
      return _this.retrieve(path);
    });
  },

  _update: function(type, data) {
    var record = this.normalize(type, data);
    var id = this.getId(type, record);

    return this.transform(this.schema.operationEncoder.replaceRecordOp(type, id, record));
  },

  _patch: function(type, id, attribute, value) {
    id = this._normalizeId(type, id);
    // todo - confirm this simplification is valid (i.e. don't attempt to deserialize attribute path)
    return this.transform(this.schema.operationEncoder.replaceAttributeOp(type, id, attribute, value));
  },

  _remove: function(type, id) {
    id = this._normalizeId(type, id);
    return this.transform(this.schema.operationEncoder.removeRecordOp(type, id));
  },

  _addLink: function(type, id, key, value) {
    id = this._normalizeId(type, id);
    value = this._normalizeLink(type, key, value);

    return this.transform(this.schema.operationEncoder.addLinkOp(type, id, key, value));
  },

  _removeLink: function(type, id, key, value) {
    id = this._normalizeId(type, id);
    value = this._normalizeLink(type, key, value);

    return this.transform(this.schema.operationEncoder.removeLinkOp(type, id, key, value));
  },

  _updateLink: function(type, id, key, value) {
    var linkDef = this.schema.models[type].links[key];

    assert('hasMany links can only be replaced when flagged as `actsAsSet`',
           linkDef.type !== 'hasMany' || linkDef.actsAsSet);

    id = this._normalizeId(type, id);
    value = this._normalizeLink(type, key, value);

    var op = this.schema.operationEncoder.replaceLinkOp(type, id, key, value);
    return this.transform(op);
  },

  /////////////////////////////////////////////////////////////////////////////
  // Helpers
  /////////////////////////////////////////////////////////////////////////////

  _normalizeId: function(type, id) {
    if (isObject(id)) {
      var record = this.normalize(type, id);
      id = this.getId(type, record);
    }
    return id;
  },

  _normalizeLink: function(type, key, value) {
    if (isObject(value)) {
      var linkDef = this.schema.models[type].links[key];
      var relatedRecord;

      if (isArray(value)) {
        for (var i = 0, l = value.length; i < l; i++) {
          if (isObject(value[i])) {
            relatedRecord = this.normalize(linkDef.model, value[i]);
            value[i] = this.getId(linkDef.model, relatedRecord);
          }
        }

      } else {
        relatedRecord = this.normalize(linkDef.model, value);
        value = this.getId(linkDef.model, relatedRecord);
      }
    }
    return value;
  },

  normalize: function(type, data) {
    return this.schema.normalize(type, data);
  },

  initDefaults: function(type, record) {
    return this.schema.initDefaults(type, record);
  },

  getId: function(type, data) {
    if (isObject(data)) {
      return data[this.schema.models[type].primaryKey.name];
    } else {
      return data;
    }
  },

  /////////////////////////////////////////////////////////////////////////////
  // Internals
  /////////////////////////////////////////////////////////////////////////////

  _isLinkEmpty: function(linkType, linkValue) {
    return (linkType === 'hasMany' && linkValue && linkValue.length === 0 ||
            linkType === 'hasOne' && isNone(linkValue));
  }
});

/**
 * A place to track the creation of any Source, is called in the Source init
 * method.  The source might not be fully configured / setup by the time you
 * receive it, but we provide this hook for potential debugging tools to monitor
 * all sources.
 *
 * @namespace OC
 * @param {OC.Source} source The newly forged Source.
 */
Source.created = function(/* source */) {};

export default Source;
<commit_msg>Expose `exists` and `hasDeleted` on Source from its `_cache`.<commit_after>import Orbit from 'orbit/main';
import Document from 'orbit/document';
import Transformable from 'orbit/transformable';
import Requestable from 'orbit/requestable';
import { assert } from 'orbit/lib/assert';
import { required } from 'orbit/lib/stubs';
import { Class, expose, isArray, isObject, isNone } from 'orbit/lib/objects';
import Cache from './cache';
import Operation from 'orbit/operation';
import { LinkNotFoundException } from './lib/exceptions';

/**
 `Source` is an abstract base class to be extended by other sources.

 @class Source
 @namespace OC
 @param {OC.Schema} [schema]
 @param {Object}    [options]
 @param {Boolean}   [options.useCache] Should source use a cache?
 @param {Object}    [options.cacheOptions] Options for cache, if used.
 @constructor
*/
var Source = Class.extend({
  init: function(schema, options) {
    assert("Source's `schema` must be specified", schema);

    this.schema = schema;

    options = options || {};

    // Create an internal cache and expose some elements of its interface
    if (options.useCache) {
      this._cache = new Cache(schema, options.cacheOptions);
      expose(this, this._cache, 'length', 'reset', 'retrieve', 'retrieveLink', 'exists', 'hasDeleted');
    }

    Transformable.extend(this);
    Requestable.extend(this, ['find', 'add', 'update', 'patch', 'remove',
                              'findLink', 'addLink', 'removeLink', 'updateLink',
                              'findLinked']);

    Source.created(this);
  },

  /////////////////////////////////////////////////////////////////////////////
  // Transformable interface implementation
  /////////////////////////////////////////////////////////////////////////////

  /**
   Internal method that applies a single transform to this source.

   `_transform` must be implemented by a `Transformable` source.
   It is called by the public method `transform` in order to actually apply
   transforms.

   `_transform` should return a promise if the operation is asynchronous.

   @method _transform
   @param operation JSON PATCH operation as detailed in RFC 6902
   @private
   */
  _transform: required,

  /////////////////////////////////////////////////////////////////////////////
  // Requestable interface implementation
  /////////////////////////////////////////////////////////////////////////////

  _find: required,

  _findLink: required,

  _findLinked: function(type, id, link, options) {
    var modelId = this.getId(type, id);
    var linkType = this.schema.linkDefinition(type, link).model;
    var linkValue = this.retrieveLink(type, modelId, link);

    if (linkValue === undefined) throw new LinkNotFoundException(type, id, link);
    if (linkValue === null) return null;

    return this._find(linkType, linkValue, options);
  },

  _add: function(type, data) {
    data = data || {};

    var record = this.normalize(type, data);

    var id = this.getId(type, record),
        path = [type, id],
        _this = this;

    return this.transform(this.schema.operationEncoder.addRecordOp(type, id, record)).then(function() {
      return _this.retrieve(path);
    });
  },

  _update: function(type, data) {
    var record = this.normalize(type, data);
    var id = this.getId(type, record);

    return this.transform(this.schema.operationEncoder.replaceRecordOp(type, id, record));
  },

  _patch: function(type, id, attribute, value) {
    id = this._normalizeId(type, id);
    // todo - confirm this simplification is valid (i.e. don't attempt to deserialize attribute path)
    return this.transform(this.schema.operationEncoder.replaceAttributeOp(type, id, attribute, value));
  },

  _remove: function(type, id) {
    id = this._normalizeId(type, id);
    return this.transform(this.schema.operationEncoder.removeRecordOp(type, id));
  },

  _addLink: function(type, id, key, value) {
    id = this._normalizeId(type, id);
    value = this._normalizeLink(type, key, value);

    return this.transform(this.schema.operationEncoder.addLinkOp(type, id, key, value));
  },

  _removeLink: function(type, id, key, value) {
    id = this._normalizeId(type, id);
    value = this._normalizeLink(type, key, value);

    return this.transform(this.schema.operationEncoder.removeLinkOp(type, id, key, value));
  },

  _updateLink: function(type, id, key, value) {
    var linkDef = this.schema.models[type].links[key];

    assert('hasMany links can only be replaced when flagged as `actsAsSet`',
           linkDef.type !== 'hasMany' || linkDef.actsAsSet);

    id = this._normalizeId(type, id);
    value = this._normalizeLink(type, key, value);

    var op = this.schema.operationEncoder.replaceLinkOp(type, id, key, value);
    return this.transform(op);
  },

  /////////////////////////////////////////////////////////////////////////////
  // Helpers
  /////////////////////////////////////////////////////////////////////////////

  _normalizeId: function(type, id) {
    if (isObject(id)) {
      var record = this.normalize(type, id);
      id = this.getId(type, record);
    }
    return id;
  },

  _normalizeLink: function(type, key, value) {
    if (isObject(value)) {
      var linkDef = this.schema.models[type].links[key];
      var relatedRecord;

      if (isArray(value)) {
        for (var i = 0, l = value.length; i < l; i++) {
          if (isObject(value[i])) {
            relatedRecord = this.normalize(linkDef.model, value[i]);
            value[i] = this.getId(linkDef.model, relatedRecord);
          }
        }

      } else {
        relatedRecord = this.normalize(linkDef.model, value);
        value = this.getId(linkDef.model, relatedRecord);
      }
    }
    return value;
  },

  normalize: function(type, data) {
    return this.schema.normalize(type, data);
  },

  initDefaults: function(type, record) {
    return this.schema.initDefaults(type, record);
  },

  getId: function(type, data) {
    if (isObject(data)) {
      return data[this.schema.models[type].primaryKey.name];
    } else {
      return data;
    }
  },

  /////////////////////////////////////////////////////////////////////////////
  // Internals
  /////////////////////////////////////////////////////////////////////////////

  _isLinkEmpty: function(linkType, linkValue) {
    return (linkType === 'hasMany' && linkValue && linkValue.length === 0 ||
            linkType === 'hasOne' && isNone(linkValue));
  }
});

/**
 * A place to track the creation of any Source, is called in the Source init
 * method.  The source might not be fully configured / setup by the time you
 * receive it, but we provide this hook for potential debugging tools to monitor
 * all sources.
 *
 * @namespace OC
 * @param {OC.Source} source The newly forged Source.
 */
Source.created = function(/* source */) {};

export default Source;
<|endoftext|>


<commit_before>// @flow
import React, { Component } from 'react';
import Peaks from '../../node_modules/peaks.js/peaks.js';
import styles from './WaveformPeaks.css';
import Colors from './Colors';
import LoadingDots from './LoadingDots';

class WaveformPeaks extends Component {
    props: {
       filePath: string,
       pos: number,
       handlePosChange: Function,
       playing: boolean
    };

    constructor(props) {
        super(props);

        this.state = {
            width: '100%',
            loading: true
        };

        this.ctx = new AudioContext();

        this.resolveContainerPromise = null;

        this.container = new Promise((resolve, reject) => {
            this.resolveContainerPromise = resolve;
        });

        this.container.then((container) => {
            window.addEventListener('resize', this.adjustContainer.bind(this, container));
        });

        this.onAudio = this.onAudio.bind(this);
        this.onContainer = this.onContainer.bind(this);
    }

    componentDidUpdate(prevProps, prevState) {
        if(prevProps.filePath !== this.props.filePath) {
            window.clearTimeout(this.timeoutId);
            this.audio.src = this.props.filePath;
            this.setState({
                width: '100%',
                loading: true
            });
        }

        if(this.props.playing && !prevProps.playing) {
            this.audio.play();
        } else if(!this.props.playing && prevProps.playing) {
            this.audio.pause();
        }
    }

    addSegments() {
        // Need to optimize this
        console.log('addSegments')
        const peaks = this.peaks;
        const { segments, fileName } = this.props;

        if(peaks.segments && peaks.segments.add && peaks.segments.removeAll) {

            peaks.segments.removeAll()
            segments.forEach(({ startTimeSeconds, endTimeSeconds, id }, index) => {
                peaks.segments.add({
                    startTime: startTimeSeconds,
                    endTime: endTimeSeconds,
                    color: Colors[index],
                    labelText: `${fileName}_${index + 1}`,
                    id,
                    editable: true
                });
            });
        }
    }

    adjustContainer(container, callback = () => {}) {
        console.log('adjustContainer', container);
        const maxWidth = this.audio.duration * 92;
        let width = '100%';
        if(container.offsetWidth > maxWidth) {
            console.log('have to shrink waveform container');
            width = `${maxWidth}px`;
        }

        this.setState({ width }, callback);
    }

    onAudio(audio) {
        console.log('save audio ref', audio);
        this.audio = audio;
        this.audio.addEventListener('loadedmetadata', () => {
            console.log('audio loadedmetadata', 'src', audio.currentSrc, 'duration', audio.duration);
            this.container.then((container) => {
                this.adjustContainer(container, () => {
                    this.initPeaks(container, audio);
                });
            });
        });
        this.audio.addEventListener('timeupdate', (e) => {
            console.log('audio timeupdate', this.audio.currentTime);
            // this isn't very smooth; switch to requestAnimationFrame
            this.props.handlePosChange(this.audio.currentTime);
        });
    }

    onContainer(container) {
        console.log('save container ref');
        this.containerSet = true;
        this.resolveContainerPromise(container);
    }

    initPeaks(container, audio) {
        console.log('initPeaks');

        if(this.peaks) {
            console.log('destroy peaks');
            this.peaks.destroy();
            this.peaks = null;
        }

        const { segments, fileName } = this.props;
        const ctx = this.ctx;

        this.peaks = Peaks.init({
            container: container,
            mediaElement: audio,
            audioContext: ctx,
            height: 100,
            zoomWaveformColor: 'rgba(0, 225, 128, 1)',
            playheadColor: '#D62B70',
            segments: segments.map(({ startTimeSeconds, endTimeSeconds, id }, index) => {
                return {
                    startTime: startTimeSeconds,
                    endTime: endTimeSeconds,
                    color: Colors[index],
                    labelText: `${fileName}_${index + 1}`,
                    id,
                    editable: true
                };
            })
        });

        this.peaks.on('error', (err) => {
            console.log('peaks had an error', err);
        });

        this.peaks.on('segments.ready', () => {
            console.log('peaks segments ready');
            //this.addSegments();
            this.timeoutId = window.setTimeout(() => {
                this.setState({ loading: false });
            }, 400);
        });

        this.peaks.on('user_seek.overview', (pos) => {
            console.log('user_seek.overview', pos);
        });

        this.peaks.on('user_seek.zoomview', (pos) => {
            console.log('user_seek.zoomview', pos);
        });

    }

    render() {

        const { filePath, pos, handlePosChange, playing } = this.props;
        const { loading, width } = this.state;
        console.log('render waveform. loading: ', loading);

        return (

                {loading &&
<LoadingDots/>
}

 { !this.containerSet && this.onContainer(container); }} className={styles.waveform} style={{ width: width }}>

                <audio ref={(audio) => { !this.audio && this.onAudio(audio); }}  src={filePath}/>

        );
    }
}

export default WaveformPeaks;<commit_msg>add future peaks.js import statement<commit_after>// @flow
import React, { Component } from 'react';
import Peaks from '../../node_modules/peaks.js/peaks.js';
//import Peaks from 'peaks.js';
import styles from './WaveformPeaks.css';
import Colors from './Colors';
import LoadingDots from './LoadingDots';

class WaveformPeaks extends Component {
    props: {
       filePath: string,
       pos: number,
       handlePosChange: Function,
       playing: boolean
    };

    constructor(props) {
        super(props);

        this.state = {
            width: '100%',
            loading: true
        };

        this.ctx = new AudioContext();

        this.resolveContainerPromise = null;

        this.container = new Promise((resolve, reject) => {
            this.resolveContainerPromise = resolve;
        });

        this.container.then((container) => {
            window.addEventListener('resize', this.adjustContainer.bind(this, container));
        });

        this.onAudio = this.onAudio.bind(this);
        this.onContainer = this.onContainer.bind(this);
    }

    componentDidUpdate(prevProps, prevState) {
        if(prevProps.filePath !== this.props.filePath) {
            window.clearTimeout(this.timeoutId);
            this.audio.src = this.props.filePath;
            this.setState({
                width: '100%',
                loading: true
            });
        }

        if(this.props.playing && !prevProps.playing) {
            this.audio.play();
        } else if(!this.props.playing && prevProps.playing) {
            this.audio.pause();
        }
    }

    addSegments() {
        // Need to optimize this
        console.log('addSegments')
        const peaks = this.peaks;
        const { segments, fileName } = this.props;

        if(peaks.segments && peaks.segments.add && peaks.segments.removeAll) {

            peaks.segments.removeAll()
            segments.forEach(({ startTimeSeconds, endTimeSeconds, id }, index) => {
                peaks.segments.add({
                    startTime: startTimeSeconds,
                    endTime: endTimeSeconds,
                    color: Colors[index],
                    labelText: `${fileName}_${index + 1}`,
                    id,
                    editable: true
                });
            });
        }
    }

    adjustContainer(container, callback = () => {}) {
        console.log('adjustContainer', container);
        const maxWidth = this.audio.duration * 92;
        let width = '100%';
        if(container.offsetWidth > maxWidth) {
            console.log('have to shrink waveform container');
            width = `${maxWidth}px`;
        }

        this.setState({ width }, callback);
    }

    onAudio(audio) {
        console.log('save audio ref', audio);
        this.audio = audio;
        this.audio.addEventListener('loadedmetadata', () => {
            console.log('audio loadedmetadata', 'src', audio.currentSrc, 'duration', audio.duration);
            this.container.then((container) => {
                this.adjustContainer(container, () => {
                    this.initPeaks(container, audio);
                });
            });
        });
        this.audio.addEventListener('timeupdate', (e) => {
            console.log('audio timeupdate', this.audio.currentTime);
            // this isn't very smooth; switch to requestAnimationFrame
            this.props.handlePosChange(this.audio.currentTime);
        });
    }

    onContainer(container) {
        console.log('save container ref');
        this.containerSet = true;
        this.resolveContainerPromise(container);
    }

    initPeaks(container, audio) {
        console.log('initPeaks');

        if(this.peaks) {
            console.log('destroy peaks');
            this.peaks.destroy();
            this.peaks = null;
        }

        const { segments, fileName } = this.props;
        const ctx = this.ctx;

        this.peaks = Peaks.init({
            container: container,
            mediaElement: audio,
            audioContext: ctx,
            height: 100,
            zoomWaveformColor: 'rgba(0, 225, 128, 1)',
            playheadColor: '#D62B70',
            segments: segments.map(({ startTimeSeconds, endTimeSeconds, id }, index) => {
                return {
                    startTime: startTimeSeconds,
                    endTime: endTimeSeconds,
                    color: Colors[index],
                    labelText: `${fileName}_${index + 1}`,
                    id,
                    editable: true
                };
            })
        });

        this.peaks.on('error', (err) => {
            console.log('peaks had an error', err);
        });

        this.peaks.on('segments.ready', () => {
            console.log('peaks segments ready');
            //this.addSegments();
            this.timeoutId = window.setTimeout(() => {
                this.setState({ loading: false });
            }, 400);
        });

        this.peaks.on('user_seek.overview', (pos) => {
            console.log('user_seek.overview', pos);
        });

        this.peaks.on('user_seek.zoomview', (pos) => {
            console.log('user_seek.zoomview', pos);
        });

    }

    render() {

        const { filePath, pos, handlePosChange, playing } = this.props;
        const { loading, width } = this.state;
        console.log('render waveform. loading: ', loading);

        return (

                {loading &&
<LoadingDots/>
}

 { !this.containerSet && this.onContainer(container); }} className={styles.waveform} style={{ width: width }}>

                <audio ref={(audio) => { !this.audio && this.onAudio(audio); }}  src={filePath}/>

        );
    }
}

export default WaveformPeaks;<|endoftext|>


<commit_before>import Service, {inject as service} from '@ember/service';
import moment from 'moment';
import {ghPluralize} from 'ghost-admin/helpers/gh-pluralize';
import {task} from 'ember-concurrency';

export default class MembersCountCacheService extends Service {
    @service session;
    @service store;

    cache = {};

    async count(filter) {
        const cachedValue = this.cache[filter];

        if (cachedValue && moment().diff(cachedValue.time, 'seconds') <= 60) {
            return cachedValue.count;
        }

        const count = this._countMembersTask.perform(filter);

        this.cache[filter] = {count, time: moment()};

        return count;
    }

    async countString(filter = '', {knownCount} = {}) {
        const user = this.session.user;

        const basicFilter = filter.replace(/^subscribed:true\+\((.*)\)$/, '$1');
        const filterParts = basicFilter.split(',');
        const isFree = filterParts.length === 1 && filterParts[0] === 'status:free';
        const isPaid = filterParts.length === 1 && filterParts[0] === 'status:-free';
        const isAll = !filter || (filterParts.includes('status:free') && filterParts.includes('status:-free'));

        // editors don't have permission to browse members so can't retrieve a count
        // TODO: remove when editors have relevant permissions or we have a different way of fetching counts
        if (user.isEditor && knownCount === undefined) {
            if (isFree) {
                return 'all free members';
            }
            if (isPaid) {
                return 'all paid members';
            }
            if (isAll) {
                return 'all members';
            }

            return 'a custom members segment';
        }

        const recipientCount = knownCount !== undefined ? knownCount : await this.count(filter);

        if (isFree) {
            return ghPluralize(recipientCount, 'free member');
        }

        if (isPaid) {
            return ghPluralize(recipientCount, 'paid member');
        }

        return ghPluralize(recipientCount, 'member');
    }

    @task
    *_countMembersTask(filter) {
        if (!filter) {
            return 0;
        }

        try {
            const result = yield this.store.query('member', {filter, limit: 1, page: 1});
            return result.meta.pagination.total;
        } catch (e) {
            console.error(e); // eslint-disable-line
            return 0;
        }
    }
}
<commit_msg>Updated `countString` formatting in `members-count-cache`<commit_after>import Service, {inject as service} from '@ember/service';
import moment from 'moment';
import {ghPluralize} from 'ghost-admin/helpers/gh-pluralize';
import {task} from 'ember-concurrency';

export default class MembersCountCacheService extends Service {
    @service session;
    @service store;

    cache = {};

    async count(filter) {
        const cachedValue = this.cache[filter];

        if (cachedValue && moment().diff(cachedValue.time, 'seconds') <= 60) {
            return cachedValue.count;
        }

        const count = this._countMembersTask.perform(filter);

        this.cache[filter] = {count, time: moment()};

        return count;
    }

    async countString(filter = '', {knownCount} = {}) {
        const user = this.session.user;

        const basicFilter = filter.replace(/^newsletters\.status:active\+\((.*)\)$/, '$1');
        const filterParts = basicFilter.split(',');
        const isFree = filterParts.length === 1 && filterParts[0] === 'status:free';
        const isPaid = filterParts.length === 1 && filterParts[0] === 'status:-free';
        const isAll = !filter || (filterParts.includes('status:free') && filterParts.includes('status:-free'));

        // editors don't have permission to browse members so can't retrieve a count
        // TODO: remove when editors have relevant permissions or we have a different way of fetching counts
        if (user.isEditor && knownCount === undefined) {
            if (isFree) {
                return 'all free members';
            }
            if (isPaid) {
                return 'all paid members';
            }
            if (isAll) {
                return 'all members';
            }

            return 'a custom members segment';
        }

        const recipientCount = knownCount !== undefined ? knownCount : await this.count(filter);

        if (isFree) {
            return ghPluralize(recipientCount, 'free member');
        }

        if (isPaid) {
            return ghPluralize(recipientCount, 'paid member');
        }

        return ghPluralize(recipientCount, 'member');
    }

    @task
    *_countMembersTask(filter) {
        if (!filter) {
            return 0;
        }

        try {
            const result = yield this.store.query('member', {filter, limit: 1, page: 1});
            return result.meta.pagination.total;
        } catch (e) {
            console.error(e); // eslint-disable-line
            return 0;
        }
    }
}
<|endoftext|>


<commit_before>process.env.NODE_ENV = 'test';
process.argv[2] = 'test';

var http = require('http');
var util = require('util');
var assert = require('assert');
var exec = require('child_process').exec;
var path = require('path');
var fs = require('fs');
var basedir = path.resolve(__dirname + '/..');

process.env.HOME = path.resolve(__dirname + '/../fixtures/files');

// Remove stale config file if present.
try { fs.unlinkSync(process.env.HOME + '/.tilemill/config.json'); }
catch (err) { if (err.code !== 'ENOENT') throw err }

// Load application.
require('../..');
var tilemill = require('bones').plugin;
tilemill.config.files = path.resolve(__dirname + '/../fixtures/files');
tilemill.config.examples = false;

module.exports.start = function(done) {
    // Create a clean environment.
    var clean = '\
        rm -f ' + basedir + '/fixtures/files/app.db && \
        rm -rf ' + basedir + '/fixtures/files/project && \
        rm -rf ' + basedir + '/fixtures/files/data && \
        rm -rf ' + basedir + '/fixtures/files/export && \
        cp -R ' + basedir + '/fixtures/pristine/project ' + basedir + '/fixtures/files';
    exec(clean, function(err) {
        if (err) throw err;
        console.warn('Initialized test fixture');
        var command = tilemill.start(function() {
            done(command);
        });
    });
};

module.exports.startPostgis = function(done) {
    var insert = '\
        psql -d postgres -c "DROP DATABASE IF EXISTS tilemill_test;" && \
        createdb -E UTF8 -T template_postgis tilemill_test && \
        psql -d tilemill_test -f ' + basedir + '/fixtures/tilemill_test.sql';
    exec(insert, function(err) {
        if (err) throw err;
        console.warn('Inserted postgres fixture.');
        module.exports.start(done);
    });
};

/**
 * Assert response from `server` with
 * the given `req` object and `res` assertions object.
 *
 * @param {Server} server
 * @param {Object} req
 * @param {Object|Function} res
 * @param {String} msg
 */
assert.response = function(server, req, res, msg) {
    // Callback as third or fourth arg
    var callback = typeof res === 'function'
        ? res
        : typeof msg === 'function'
            ? msg
            : function() {};

    // Default message to test title
    if (typeof msg === 'function') msg = null;
    msg = msg || '';

    // Issue request
    var timer,
        method = req.method || 'GET',
        status = res.status || res.statusCode,
        data = req.data || req.body,
        requestTimeout = req.timeout || 0,
        encoding = req.encoding || 'utf8';

    var request = http.request({
        host: '127.0.0.1',
        port: server.port,
        path: req.url,
        method: method,
        headers: req.headers
    });

    var check = function() {
        if (--server.__pending === 0) {
            server.close();
            server.__listening = false;
        }
    };

    // Timeout
    if (requestTimeout) {
        timer = setTimeout(function() {
            check();
            delete req.timeout;
            throw new Error(msg + 'Request timed out after ' + requestTimeout + 'ms.');
        }, requestTimeout);
    }

    if (data) request.write(data);

    request.on('response', function(response) {
        response.body = '';
        response.setEncoding(encoding);
        response.on('data', function(chunk) { response.body += chunk; });
        response.on('end', function() {
            if (timer) clearTimeout(timer);
            // Assert response body
            if (res.body !== undefined) {
                var eql = res.body instanceof RegExp
                  ? res.body.test(response.body)
                  : res.body === response.body;
                assert.ok(
                    eql,
                    msg + 'Invalid response body.\n'
                        + '    Expected: ' + util.inspect(res.body) + '\n'
                        + '    Got: ' + util.inspect(response.body)
                );
            }

            // Assert response status
            if (typeof status === 'number') {
                assert.equal(
                    response.statusCode,
                    status,
                    msg + 'Invalid response status code.\n'
                        + '     Expected: ' + status + '\n'
                        + '     Got: ' + response.statusCode + ''
                );
            }

            // Assert response headers
            if (res.headers) {
                var keys = Object.keys(res.headers);
                for (var i = 0, len = keys.length; i < len; ++i) {
                    var name = keys[i],
                        actual = response.headers[name.toLowerCase()],
                        expected = res.headers[name],
                        eql = expected instanceof RegExp
                          ? expected.test(actual)
                          : expected == actual;
                        assert.ok(
                            eql,
                            msg + 'Invalid response header ' + name + '.\n'
                                + '    Expected: ' + expected + '\n'
                                + '    Got: ' + actual
                        );
                }
            }
            // Callback
            callback(response);
        });
    });

    request.end();

};

/**
 * Assert that `str` matches `regexp`.
 *
 * @param {String} str
 * @param {RegExp} regexp
 * @param {String} msg
 */
assert.match = function(str, regexp, msg) {
    msg = msg || util.inspect(str) + ' does not match ' + util.inspect(regexp);
    assert.ok(regexp.test(str), msg);
};

<commit_msg>for test failures due to failed http status be nice and show the response<commit_after>process.env.NODE_ENV = 'test';
process.argv[2] = 'test';

var http = require('http');
var util = require('util');
var assert = require('assert');
var exec = require('child_process').exec;
var path = require('path');
var fs = require('fs');
var basedir = path.resolve(__dirname + '/..');

process.env.HOME = path.resolve(__dirname + '/../fixtures/files');

// Remove stale config file if present.
try { fs.unlinkSync(process.env.HOME + '/.tilemill/config.json'); }
catch (err) { if (err.code !== 'ENOENT') throw err }

// Load application.
require('../..');
var tilemill = require('bones').plugin;
tilemill.config.files = path.resolve(__dirname + '/../fixtures/files');
tilemill.config.examples = false;

module.exports.start = function(done) {
    // Create a clean environment.
    var clean = '\
        rm -f ' + basedir + '/fixtures/files/app.db && \
        rm -rf ' + basedir + '/fixtures/files/project && \
        rm -rf ' + basedir + '/fixtures/files/data && \
        rm -rf ' + basedir + '/fixtures/files/export && \
        cp -R ' + basedir + '/fixtures/pristine/project ' + basedir + '/fixtures/files';
    exec(clean, function(err) {
        if (err) throw err;
        console.warn('Initialized test fixture');
        var command = tilemill.start(function() {
            done(command);
        });
    });
};

module.exports.startPostgis = function(done) {
    var insert = '\
        psql -d postgres -c "DROP DATABASE IF EXISTS tilemill_test;" && \
        createdb -E UTF8 -T template_postgis tilemill_test && \
        psql -d tilemill_test -f ' + basedir + '/fixtures/tilemill_test.sql';
    exec(insert, function(err) {
        if (err) throw err;
        console.warn('Inserted postgres fixture.');
        module.exports.start(done);
    });
};

/**
 * Assert response from `server` with
 * the given `req` object and `res` assertions object.
 *
 * @param {Server} server
 * @param {Object} req
 * @param {Object|Function} res
 * @param {String} msg
 */
assert.response = function(server, req, res, msg) {
    // Callback as third or fourth arg
    var callback = typeof res === 'function'
        ? res
        : typeof msg === 'function'
            ? msg
            : function() {};

    // Default message to test title
    if (typeof msg === 'function') msg = null;
    msg = msg || '';

    // Issue request
    var timer,
        method = req.method || 'GET',
        status = res.status || res.statusCode,
        data = req.data || req.body,
        requestTimeout = req.timeout || 0,
        encoding = req.encoding || 'utf8';

    var request = http.request({
        host: '127.0.0.1',
        port: server.port,
        path: req.url,
        method: method,
        headers: req.headers
    });

    var check = function() {
        if (--server.__pending === 0) {
            server.close();
            server.__listening = false;
        }
    };

    // Timeout
    if (requestTimeout) {
        timer = setTimeout(function() {
            check();
            delete req.timeout;
            throw new Error(msg + 'Request timed out after ' + requestTimeout + 'ms.');
        }, requestTimeout);
    }

    if (data) request.write(data);

    request.on('response', function(response) {
        response.body = '';
        response.setEncoding(encoding);
        response.on('data', function(chunk) { response.body += chunk; });
        response.on('end', function() {
            if (timer) clearTimeout(timer);
            // Assert response body
            if (res.body !== undefined) {
                var eql = res.body instanceof RegExp
                  ? res.body.test(response.body)
                  : res.body === response.body;
                assert.ok(
                    eql,
                    msg + 'Invalid response body.\n'
                        + '    Expected: ' + util.inspect(res.body) + '\n'
                        + '    Got: ' + util.inspect(response.body)
                );
            }

            // Assert response status
            if (typeof status === 'number') {
                assert.equal(
                    response.statusCode,
                    status,
                    msg + 'Invalid response status code.\n'
                        + '     Expected: ' + status + '\n'
                        + '     Got: ' + response.statusCode + '' + response.body
                );
            }

            // Assert response headers
            if (res.headers) {
                var keys = Object.keys(res.headers);
                for (var i = 0, len = keys.length; i < len; ++i) {
                    var name = keys[i],
                        actual = response.headers[name.toLowerCase()],
                        expected = res.headers[name],
                        eql = expected instanceof RegExp
                          ? expected.test(actual)
                          : expected == actual;
                        assert.ok(
                            eql,
                            msg + 'Invalid response header ' + name + '.\n'
                                + '    Expected: ' + expected + '\n'
                                + '    Got: ' + actual
                        );
                }
            }
            // Callback
            callback(response);
        });
    });

    request.end();

};

/**
 * Assert that `str` matches `regexp`.
 *
 * @param {String} str
 * @param {RegExp} regexp
 * @param {String} msg
 */
assert.match = function(str, regexp, msg) {
    msg = msg || util.inspect(str) + ' does not match ' + util.inspect(regexp);
    assert.ok(regexp.test(str), msg);
};

<|endoftext|>


<commit_before>/*
 * Url module. Required for resolving relative paths.
 */

var url = require("url");

/*
 * Regexp from origin Arc90 Readability.
 */

var regexps = {
  unlikelyCandidatesRe: /combx|pager|comment|disqus|foot|header|menu|meta|nav|rss|shoutbox|sidebar|sponsor|share|bookmark|social|advert|leaderboard|instapaper_ignore|entry-unrelated/i,
  okMaybeItsACandidateRe: /and|article|body|column|main/i,
  positiveRe: /article|body|content|entry|hentry|page|pagination|post|text/i,
  negativeRe: /combx|comment|captcha|contact|foot|footer|footnote|link|media|meta|promo|related|scroll|shoutbox|sponsor|utility|tags|widget|tip|dialog/i,
  divToPElementsRe: /<(a|blockquote|dl|div|img|ol|p|pre|table|ul)/i,
  replaceBrsRe: /(
]*>[ \n\r\t]*){2,}/gi,
  replaceFontsRe: /<(\/?)font[^>]*>/gi,
  trimRe: /^\s+|\s+$/g,
  normalizeRe: /\s{2,}/g,
  killBreaksRe: /(
(\s| ?)*){1,}/g,
  videoRe: /http:\/\/(www\.)?(youtube|vimeo|youku|tudou|56|yinyuetai)\.com/i
};

/**
 * Node Types and their classification
 **/

var nodeTypes = {
  'mostPositive': ['div'],
  'positive': ['pre', 'td', 'blockquote'],
  'negative': ['address', 'ol', 'ul', 'dl', 'dd', 'dt', 'li'],
  'mostNegative': ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'th']
}

/**
 * We're getting only the readable content + images, no other nodes are needed.
 **/

var trashNodes = 'meta,iframe,noscript,style,aside,object,script';

/**
 * Select the TopCandidate from all possible candidates
 **/

function getArticle(candidates, $, options) {
  var topCandidate = null;

  candidates.forEach(function(elem) {
    var linkDensity = getLinkDensity(elem, $);
    var score = elem.data('readabilityScore');
    // actually say, we can't score node by children length
    // e.g.: sometimes, the comments of an article have lots of children,
    // such as: like, dislike, follow, print, star+/-...
    // but most of them worthless.
    // var siblings = elem.children().length;

    elem.data('readabilityScore', /*Math.max(2, siblings) * */ score * (1 - linkDensity));
    if (!topCandidate || elem.data('readabilityScore') > topCandidate.data('readabilityScore')) {
      topCandidate = elem;
    }
  });
  /**
   * If we still have no top candidate, just use the body as a last resort.
   * We also have to copy the body node so it is something we can modify.
   **/
  if (topCandidate === null) {
    // With no top candidate, bail out if no body tag exists as last resort.
    if (!$('body')) return new Error("No body tag was found.");
    return $('body');
  }
  // Perhaps the topCandidate is the parent?
  var parent;
  if (!(parent = topCandidate.parent()) || parent.length == 0 || topCandidate.children('p').length > 5) {
    return filterCandidates(topCandidate, topCandidate.children(), $);
  } else {
    return filterCandidates(topCandidate, parent.children(), $);
  }
}

/**
 * Filter TopCandidate Siblings (Children) based on their Link Density, and readabilityScore
 * Append the nodes to articleContent
 **/

function filterCandidates(topCandidate, siblings, $) {
  var articleContent = $("

");
  var siblingScoreThreshold = Math.max(10, topCandidate.data('readabilityScore') * 0.2);
  siblings.each(function(index, elem) {
    var sibling = $(this);
    var append = false;
    var type = sibling.get(0).name;
    var score = sibling.data('readabilityScore');
    var children = siblings.contents().length;
    if (sibling === topCandidate || score > siblingScoreThreshold) {
      append = true;
    }
    if (children > 0) {
      siblings.contents().each(function(index, elem) {
        if (elem.name == "img") append = true;
      });
    }

    if (!append && type == 'p') {
      var linkDensity = getLinkDensity(sibling, $);
      var len = sibling.text().length;
      if (len < 3) return;

      if (len > 80 && linkDensity < 0.25) {
        append = true;
      } else if (len < 80 && linkDensity == 0 && sibling.text().replace(regexps.trimRe, "")) {
        append = true;
      }
    }
    if (append) {
      articleContent.append(sibling);
    }
  });
  return articleContent;
}

/**
 * Traverse all Nodes and remove unlikely Candidates.
 **/

function getCandidates($, base, options) {

  $(trashNodes).remove();
  // Candidates Array
  var candidates = [];

  // Iterate over all Nodes in body
  $('*', 'body').each(function(index, element) {
    var node = $(this);

    // If node is null, return, otherwise Illegal Access Error
    if (!node || node.length == 0) return;
    var nodeType = node.get(0).name;

    // Remove Unlikely Candidates
    var classAndID = (node.attr('class') || "") + (node.attr('id') || "");
    if (classAndID.search(regexps.unlikelyCandidatesRe) !== -1 && classAndID.search(regexps.okMaybeItsACandidateRe) == -1) {
      node.remove();
      return;
    }

    // Remove Elements that have no children and have no content
    if (nodeType == "div" && node.children().length < 1 && node.text().trim().length < 1) {
      node.remove();
      return;
    }
    // Remove Style
    node.removeAttr('style');

    // turn all divs that don't have children block level elements into p's
    if (nodeType === "div" && options.considerDIVs) {
      if (node.html().search(regexps.divToPElementsRe) === -1) {
        node.replaceWith('
' + node.html() + '
');
      } else {
        node.contents().each(function(index, element){
          var child = $(this), childEntity;
          if(!child || !(childEntity = child.get(0))){
            return;
          }
          if(childEntity.type == 'text' && childEntity.data && childEntity.data.replace(regexps.trimRe, '').length > 0){
            child.replaceWith('
' + childEntity.data + '
');
          }
        });
      }
    }

    // score paragraphs.
    if (nodeType == "p") {
      calculateNodeScore(node, candidates);
      return;
    }

    // Resolve URLs
    if (base) {
      if (nodeType == "img" && typeof node.attr('href') != "undefined") {
        node.attr('src', url.resolve(base, node.attr('src')));
      }
      if (nodeType == "a" && typeof node.attr('href') != "undefined") {
        node.attr('href', url.resolve(base, node.attr('href')));
      }
    }

    // Clean the headers
    if (["h1", "h2", "h3", "h4", "h5", "h6"].indexOf(nodeType) !== -1) {
      var weight = getClassWeight(node, $);
      var density = getLinkDensity(node, $);
      if (weight < 0 || density > 0.3) {
        node.remove();
      }
    }

  });
  // calculate scores of `P`s that were turned from DIV by us.
  $('p.node-read-div2p', 'body').each(function(){
    calculateNodeScore($(this), candidates);
  });
  return candidates;
}

/**
 * save score datas to nodes need score.
 * @param node
 * @param contentScore
 * @param candidates
 */
function scoreCandidate(node, contentScore, candidates) {
  var score;
  if (typeof node.data('readabilityScore') == "undefined") {
    score = initializeNode(node);
    candidates.push(node);
  } else {
    score = node.data('readabilityScore') || 0;
  }
  node.data('readabilityScore', score + contentScore)
}

/**
 * calculate score of specified node.
 * @param node
 * @param candidates
 */
function calculateNodeScore(node, candidates){
  var txt = node.text();
  // Ignore too small nodes
  if (txt.length < 25) return;

  var contentScore = 0;

  // Add a point for the paragraph itself as a base.
  ++contentScore;

  // Add points for any commas within this paragraph
  // support Chinese commas.
  var commas = txt.match(/[,，.。;；?？、]/g);
  if (commas && commas.length) {
    contentScore += commas.length;
  }

  // For every 100 characters in this paragraph, add another point. Up to 3 points.
  contentScore += Math.min(Math.floor(txt.length / 100), 3);

  // Initialize Parent and Grandparent
  // First initialize the parent node with contentScore / 1, then grandParentNode with contentScore / 2
  var parent = node.parent();

  if (parent && parent.length > 0) {
    scoreCandidate(parent, contentScore, candidates);
    var grandParent = parent.parent();
    if (grandParent && grandParent.length > 0) {
      scoreCandidate(grandParent, contentScore / 2, candidates);
    }
  }
}

/**
 * Check the type of node, and get its Weight
 **/

function initializeNode(node) {
  if (!node || node.length == 0) return 0;
  var tag = node.get(0).name;
  if (nodeTypes['mostPositive'].indexOf(tag)) return 5 + getClassWeight(node);
  if (nodeTypes['positive'].indexOf(tag)) return 3 + getClassWeight(node);
  if (nodeTypes['negative'].indexOf(tag)) return -3 + getClassWeight(node);
  if (nodeTypes['mostNegative'].indexOf(tag)) return -5 + getClassWeight(node);
}

/**
 * Node Weight is calculated based on className and ID of the node.
 **/

function getClassWeight(node) {
  if (node == null || node.length == 0) return 0;
  var classAndID = (node.attr('class') || "") + (node.attr('id') || "");
  var weight = 0;

  if (node.get(0).name == "article") weight += 25;
  if (classAndID.search(regexps.negativeRe) !== -1) weight -= 25;
  if (classAndID.search(regexps.positiveRe) !== -1) weight += 25;

  return weight;
}

/**
 * Get Link density of this node.
 * Total length of link text in this node divided by the total text of the node.
 * Relative links are not included.
 **/

function getLinkDensity(node, $) {
  var links = node.find('a');
  var textLength = node.text().length;
  var linkLength = 0;
  links.each(function(index, elem) {
    var href = $(this).attr('href');
    if (!href || (href.length > 0 && href[0] === '#')) return;
    linkLength += $(this).text().length;
  });
  return (linkLength / textLength) || 0;
}

/**
 * Main method
 * If the first run does not succeed, try the body element;
 **/

module.exports.extract = function($, base, options) {
  var candidates = getCandidates($, base, options);
  article = getArticle(candidates, $, options);
  if (article.length < 1) {
    article = getArticle([$('body')], $)
  }
  return article;
}<commit_msg>Critical Bug: compare two CHEERIO Object equal or not.<commit_after>/*
 * Url module. Required for resolving relative paths.
 */

var url = require("url");

/*
 * Regexp from origin Arc90 Readability.
 */

var regexps = {
  unlikelyCandidatesRe: /combx|pager|comment|disqus|foot|header|menu|meta|nav|rss|shoutbox|sidebar|sponsor|share|bookmark|social|advert|leaderboard|instapaper_ignore|entry-unrelated/i,
  okMaybeItsACandidateRe: /and|article|body|column|main/i,
  positiveRe: /article|body|content|entry|hentry|page|pagination|post|text/i,
  negativeRe: /combx|comment|captcha|contact|foot|footer|footnote|link|media|meta|promo|related|scroll|shoutbox|sponsor|utility|tags|widget|tip|dialog/i,
  divToPElementsRe: /<(a|blockquote|dl|div|img|ol|p|pre|table|ul)/i,
  replaceBrsRe: /(
]*>[ \n\r\t]*){2,}/gi,
  replaceFontsRe: /<(\/?)font[^>]*>/gi,
  trimRe: /^\s+|\s+$/g,
  normalizeRe: /\s{2,}/g,
  killBreaksRe: /(
(\s| ?)*){1,}/g,
  videoRe: /http:\/\/(www\.)?(youtube|vimeo|youku|tudou|56|yinyuetai)\.com/i
};

/**
 * Node Types and their classification
 **/

var nodeTypes = {
  'mostPositive': ['div'],
  'positive': ['pre', 'td', 'blockquote'],
  'negative': ['address', 'ol', 'ul', 'dl', 'dd', 'dt', 'li'],
  'mostNegative': ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'th']
}

/**
 * We're getting only the readable content + images, no other nodes are needed.
 **/

var trashNodes = 'meta,iframe,noscript,style,aside,object,script';

/**
 * Select the TopCandidate from all possible candidates
 **/

function getArticle(candidates, $, options) {
  var topCandidate = null;

  candidates.forEach(function(elem) {
    var linkDensity = getLinkDensity(elem, $);
    var score = elem.data('readabilityScore');
    // actually say, we can't score node by children length
    // e.g.: sometimes, the comments of an article have lots of children,
    // such as: like, dislike, follow, print, star+/-...
    // but most of them worthless.
    // var siblings = elem.children().length;

    elem.data('readabilityScore', /*Math.max(2, siblings) * */ score * (1 - linkDensity));
    if (!topCandidate || elem.data('readabilityScore') > topCandidate.data('readabilityScore')) {
      topCandidate = elem;
    }
  });
  /**
   * If we still have no top candidate, just use the body as a last resort.
   * We also have to copy the body node so it is something we can modify.
   **/
  if (topCandidate === null) {
    // With no top candidate, bail out if no body tag exists as last resort.
    if (!$('body')) return new Error("No body tag was found.");
    return $('body');
  }
  // Perhaps the topCandidate is the parent?
  var parent;
  if (!(parent = topCandidate.parent()) || parent.length == 0 || topCandidate.children('p').length > 5) {
    return filterCandidates(topCandidate, topCandidate.children(), $);
  } else {
    return filterCandidates(topCandidate, parent.children(), $);
  }
}

/**
 * Filter TopCandidate Siblings (Children) based on their Link Density, and readabilityScore
 * Append the nodes to articleContent
 **/

function filterCandidates(topCandidate, siblings, $) {
  var articleContent = $("

");
  var siblingScoreThreshold = Math.max(10, topCandidate.data('readabilityScore') * 0.2);
  siblings.each(function(index, elem) {
    var sibling = $(this);
    var append = false;
    var type = sibling.get(0).name;
    var score = sibling.data('readabilityScore');
    var children = siblings.contents().length;
    if (sibling.is(topCandidate) || score > siblingScoreThreshold) {
      append = true;
    }
    if (children > 0) {
      siblings.contents().each(function(index, elem) {
        if (elem.name == "img") append = true;
      });
    }

    if (!append && type == 'p') {
      var linkDensity = getLinkDensity(sibling, $);
      var len = sibling.text().length;
      if (len < 3) return;

      if (len > 80 && linkDensity < 0.25) {
        append = true;
      } else if (len < 80 && linkDensity == 0 && sibling.text().replace(regexps.trimRe, "")) {
        append = true;
      }
    }
    if (append) {
      articleContent.append(sibling);
    }
  });
  return articleContent;
}

/**
 * Traverse all Nodes and remove unlikely Candidates.
 **/

function getCandidates($, base, options) {

  $(trashNodes).remove();
  // Candidates Array
  var candidates = [];

  // Iterate over all Nodes in body
  $('*', 'body').each(function(index, element) {
    var node = $(this);

    // If node is null, return, otherwise Illegal Access Error
    if (!node || node.length == 0) return;
    var nodeType = node.get(0).name;

    // Remove Unlikely Candidates
    var classAndID = (node.attr('class') || "") + (node.attr('id') || "");
    if (classAndID.search(regexps.unlikelyCandidatesRe) !== -1 && classAndID.search(regexps.okMaybeItsACandidateRe) == -1) {
      node.remove();
      return;
    }

    // Remove Elements that have no children and have no content
    if (nodeType == "div" && node.children().length < 1 && node.text().trim().length < 1) {
      node.remove();
      return;
    }
    // Remove Style
    node.removeAttr('style');

    // turn all divs that don't have children block level elements into p's
    if (nodeType === "div" && options.considerDIVs) {
      if (node.html().search(regexps.divToPElementsRe) === -1) {
        node.replaceWith('
' + node.html() + '
');
      } else {
        node.contents().each(function(index, element){
          var child = $(this), childEntity;
          if(!child || !(childEntity = child.get(0))){
            return;
          }
          if(childEntity.type == 'text' && childEntity.data && childEntity.data.replace(regexps.trimRe, '').length > 0){
            child.replaceWith('
' + childEntity.data + '
');
          }
        });
      }
    }

    // score paragraphs.
    if (nodeType == "p") {
      calculateNodeScore(node, candidates);
      return;
    }

    // Resolve URLs
    if (base) {
      if (nodeType == "img" && typeof node.attr('href') != "undefined") {
        node.attr('src', url.resolve(base, node.attr('src')));
      }
      if (nodeType == "a" && typeof node.attr('href') != "undefined") {
        node.attr('href', url.resolve(base, node.attr('href')));
      }
    }

    // Clean the headers
    if (["h1", "h2", "h3", "h4", "h5", "h6"].indexOf(nodeType) !== -1) {
      var weight = getClassWeight(node, $);
      var density = getLinkDensity(node, $);
      if (weight < 0 || density > 0.3) {
        node.remove();
      }
    }

  });
  // calculate scores of `P`s that were turned from DIV by us.
  $('p.node-read-div2p', 'body').each(function(){
    calculateNodeScore($(this), candidates);
  });
  return candidates;
}

/**
 * save score datas to nodes need score.
 * @param node
 * @param contentScore
 * @param candidates
 */
function scoreCandidate(node, contentScore, candidates) {
  var score;
  if (typeof node.data('readabilityScore') == "undefined") {
    score = initializeNode(node);
    candidates.push(node);
  } else {
    score = node.data('readabilityScore') || 0;
  }
  node.data('readabilityScore', score + contentScore)
}

/**
 * calculate score of specified node.
 * @param node
 * @param candidates
 */
function calculateNodeScore(node, candidates){
  var txt = node.text();
  // Ignore too small nodes
  if (txt.length < 25) return;

  var contentScore = 0;

  // Add a point for the paragraph itself as a base.
  ++contentScore;

  // Add points for any commas within this paragraph
  // support Chinese commas.
  var commas = txt.match(/[,，.。;；?？、]/g);
  if (commas && commas.length) {
    contentScore += commas.length;
  }

  // For every 100 characters in this paragraph, add another point. Up to 3 points.
  contentScore += Math.min(Math.floor(txt.length / 100), 3);

  // Initialize Parent and Grandparent
  // First initialize the parent node with contentScore / 1, then grandParentNode with contentScore / 2
  var parent = node.parent();

  if (parent && parent.length > 0) {
    scoreCandidate(parent, contentScore, candidates);
    var grandParent = parent.parent();
    if (grandParent && grandParent.length > 0) {
      scoreCandidate(grandParent, contentScore / 2, candidates);
    }
  }
}

/**
 * Check the type of node, and get its Weight
 **/

function initializeNode(node) {
  if (!node || node.length == 0) return 0;
  var tag = node.get(0).name;
  if (nodeTypes['mostPositive'].indexOf(tag)) return 5 + getClassWeight(node);
  if (nodeTypes['positive'].indexOf(tag)) return 3 + getClassWeight(node);
  if (nodeTypes['negative'].indexOf(tag)) return -3 + getClassWeight(node);
  if (nodeTypes['mostNegative'].indexOf(tag)) return -5 + getClassWeight(node);
}

/**
 * Node Weight is calculated based on className and ID of the node.
 **/

function getClassWeight(node) {
  if (node == null || node.length == 0) return 0;
  var classAndID = (node.attr('class') || "") + (node.attr('id') || "");
  var weight = 0;

  if (node.get(0).name == "article") weight += 25;
  if (classAndID.search(regexps.negativeRe) !== -1) weight -= 25;
  if (classAndID.search(regexps.positiveRe) !== -1) weight += 25;

  return weight;
}

/**
 * Get Link density of this node.
 * Total length of link text in this node divided by the total text of the node.
 * Relative links are not included.
 **/

function getLinkDensity(node, $) {
  var links = node.find('a');
  var textLength = node.text().length;
  var linkLength = 0;
  links.each(function(index, elem) {
    var href = $(this).attr('href');
    if (!href || (href.length > 0 && href[0] === '#')) return;
    linkLength += $(this).text().length;
  });
  return (linkLength / textLength) || 0;
}

/**
 * Main method
 * If the first run does not succeed, try the body element;
 **/

module.exports.extract = function($, base, options) {
  var candidates = getCandidates($, base, options);
  article = getArticle(candidates, $, options);
  if (article.length < 1) {
    article = getArticle([$('body')], $)
  }
  return article;
}<|endoftext|>


<commit_before>var sandbox = require("sandboxed-module");

exports["module exported functions"] = function(test){

	var endpoint = require("../lib/endpoint");

	test.notEqual(endpoint.rpc,undefined);
	test.notEqual(endpoint.events, undefined);
	test.done();

}

exports["endpoint.rpc: incorrect jsonstring"] = function(test){

	var endpoint = require("../lib/endpoint");
	var req_str = '{"jsonrpc":"2.1""method":"test","id":123'; //missing ending }

	endpoint.rpc( {writeHead: function(status, header_data){

							test.equal(status, 400);
							test.deepEqual(header_data,{"Content-Type":"application/json"});
			 		},
			 		end: function( out_str ){

					 		var out_obj = JSON.parse(out_str);
					 		test.deepEqual({jsonrpc:"2.0",err:{code:-32700,message:"Parse error."}, id:null},out_obj);
					}
			} , req_str );

	test.done();

}

exports["endpoint.rpc: incorrect json-rpc version"] = function(test){

	var endpoint = require("../lib/endpoint");
	var req_str = '{"jsonrpc":"2.1","method":"test","id":123}';

	endpoint.rpc( {writeHead: function(status, header_data){

							test.equal(status, 400);
							test.deepEqual(header_data,{"Content-Type":"application/json"});
			 		},
			 		end: function( out_str ){

					 		var out_obj = JSON.parse(out_str);
					 		test.deepEqual({jsonrpc:"2.0",err:{code:-32604,message:"Version not supported."}, id:null},out_obj);

					}
			} , req_str );

	test.done();
}

exports["endpoint.rpc: method not found"] = function(test){

	var endpoint = sandbox.require("../lib/endpoint",{
		requires:{"./api":{	remote:{
							create: function(params, ret_handler){

								ret_handler(null,{wid:"1234"});

							}}
		}}
	});

	var req_str = '{"jsonrpc":"2.0","method":"nonexisting","id":123}';

	endpoint.rpc( {writeHead: function(status, header_data){

							test.equal(status, 400);
							test.deepEqual(header_data,{"Content-Type":"application/json"});
			 		},
			 		end: function( out_str ){

					 		var out_obj = JSON.parse(out_str);
					 		test.deepEqual({jsonrpc:"2.0",err:{code:-32600,message:"Method not found."}, id:"123"},out_obj);

					}
			} , req_str );

	test.done();

}

exports["endpoint.rpc: method invocation: with result, no params"] = function(test){

	var ret_value = {test:1};

	var api = {	remote:{
						test: function(params, ret_handler){

							ret_handler(null,ret_value);

						}}
			 };

	var srv = sandbox.require("../lib/server",{
		requires:{	"./api":api}
	});

	var endpoint = sandbox.require("../lib/endpoint",{
		requires:{	"./api":api,
					"./server":srv
				}
	});

	var req_str = '{"jsonrpc":"2.0","method":"test","id":123}';

	endpoint.rpc( {writeHead: function(status, header_data){

							test.equal(status, 200);
							test.deepEqual(header_data,{"Content-Type":"application/json"});
			 		},
			 		end: function( out_str ){

					 		var out_obj = JSON.parse(out_str);
					 		test.deepEqual({jsonrpc:"2.0",result:ret_value, id:"123"},out_obj);
					}
			} , req_str );

	test.done();

}

exports["endpoint.rpc: method invocation: with result, params"] = function(test){

	var req = { "jsonrpc":"2.0",
				"method":"test",
				"params":{x:1,y:2},
				"id":"123"};

	var api = {	remote:{
						test: function(params, ret_handler){

							test.deepEqual(params, req.params);
							ret_handler(null,params.x + params.y);

						}}
			 };

	var srv = sandbox.require("../lib/server",{
		requires:{	"./api":api}
	});

	var endpoint = sandbox.require("../lib/endpoint",{
		requires:{	"./api":api,
					"./server":srv
				}
	});

	var req_str = JSON.stringify(req);

	endpoint.rpc( {writeHead: function(status, header_data){

							test.equal(status, 200);
							test.deepEqual(header_data,{"Content-Type":"application/json"});
			 		},
			 		end: function( out_str ){

					 		var out_obj = JSON.parse(out_str);
					 		test.deepEqual({jsonrpc:"2.0",result:req.params.x + req.params.y, id:"123"},out_obj);
					}
			} , req_str );

	test.done();

}

exports["endpoint.rpc: method invocation: with error"] = function(test){

	var err_value = {test:1};

	var api = {	remote:{
						test: function(params, ret_handler){

							ret_handler(err_value,null);

						}}
			 };

	var srv = sandbox.require("../lib/server",{
		requires:{	"./api":api}
	});

	var endpoint = sandbox.require("../lib/endpoint",{
		requires:{	"./api":api,
					"./server":srv
				}
	});

	var req_str = '{"jsonrpc":"2.0","method":"test","id":123}';

	endpoint.rpc( {writeHead: function(status, header_data){

							test.equal(status, 200);
							test.deepEqual(header_data,{"Content-Type":"application/json"});
			 		},
			 		end: function( out_str ){

					 		var out_obj = JSON.parse(out_str);
					 		test.deepEqual({jsonrpc:"2.0",error:err_value, id:"123"},out_obj);
					}
			} , req_str );

	test.done();

}

exports["endpoint.rpc: method invocation without id"] = function(test){

	var flags = [0, 1, 1, 1];

	var api = {	remote:{
						test: function(params, ret_handler){

							flags[0] = 1;	//remote procedure gets executed.
							ret_handler(null,{});

						}}
			 };

	var srv = sandbox.require("../lib/server",{
		requires:{	"./api":api}
	});

	var endpoint = sandbox.require("../lib/endpoint",{
		requires:{	"./api":api,
					"./server":srv
				}
	});

	var req_str = '{"jsonrpc":"2.0","method":"test"}';

	endpoint.rpc( {writeHead: function(status, header_data){

					flags[1] = 0; //writeHead() does not get executed (flag not changed).
		 		 },
		 		write: function( out_str ){
		 			flags[2] = 0; //write does not get executed (flag not changed).
		 		},
		 		end: function( out_str ){

		 			flags[3] = 0; //end() does not get executed (flag not changed).
				}
		} , req_str );

	test.ok( flags[0] );
	test.ok( flags[1] );
	test.ok( flags[2] );
	test.ok( flags[3] );
	test.done();

}

exports["endpoint.events: subscribe invocation"] = function(test){

	var endpoint = sandbox.require("../lib/endpoint",{
		requires:{"./evqueue":{	remote:{
								subscribe: function( http_resp, params ){

									test.notEqual( http_resp, undefined);
									test.ok( http_resp.myhttp );
									test.deepEqual(params,{uid:620793114});
								}
							}
		}}
	});

	//json request sent to subscribe to the events channel for uid 620793114
	var req_str = '{"jsonrpc":"2.0","method":"subscribe", "params":{"uid":620793114}}';
	var http_resp = {	myhttp:true,
						writeHead: function(status, header_data){

							test.equal(status,200);
							test.deepEqual(header_data,{"Content-Type":"application/json"});
			 			},
						connection:{
							setTimeout:function(timeout){

								test.equal(timeout,0);
							},
							setNoDelay:function(flag){

								test.ok(flag);
							}
						}
					};

	endpoint.events( http_resp , req_str );

	test.expect(7);
	test.done();
}

<commit_msg>tests integrated with sandbox module.<commit_after>var sandbox = require("sandboxed-module");

exports["module exported functions"] = function(test){

	var endpoint = require("../lib/endpoint");

	test.notEqual(endpoint.rpc,undefined);
	test.notEqual(endpoint.events, undefined);
	test.done();

}

exports["endpoint.rpc: incorrect jsonstring"] = function(test){

	var endpoint = require("../lib/endpoint");
	var req_str = '{"jsonrpc":"2.1""method":"test","id":123'; //missing ending }

	endpoint.rpc( {writeHead: function(status, header_data){

							test.equal(status, 400);
							test.deepEqual(header_data,{"Content-Type":"application/json"});
			 		},
			 		end: function( out_str ){

					 		var out_obj = JSON.parse(out_str);
					 		test.deepEqual({jsonrpc:"2.0",err:{code:-32700,message:"Parse error."}, id:null},out_obj);
					}
			} , req_str );

	test.done();

}

exports["endpoint.rpc: incorrect json-rpc version"] = function(test){

	var endpoint = require("../lib/endpoint");
	var req_str = '{"jsonrpc":"2.1","method":"test","id":123}';

	endpoint.rpc( {writeHead: function(status, header_data){

							test.equal(status, 400);
							test.deepEqual(header_data,{"Content-Type":"application/json"});
			 		},
			 		end: function( out_str ){

					 		var out_obj = JSON.parse(out_str);
					 		test.deepEqual({jsonrpc:"2.0",err:{code:-32604,message:"Version not supported."}, id:null},out_obj);

					}
			} , req_str );

	test.done();
}

exports["endpoint.rpc: method not found"] = function(test){

	var endpoint = sandbox.require("../lib/endpoint",{
		requires:{"./api":{	remote:{
							create: function(params, ret_handler){

								ret_handler(null,{wid:"1234"});

							}}
		}}
	});

	var req_str = '{"jsonrpc":"2.0","method":"nonexisting","id":123}';

	endpoint.rpc( {writeHead: function(status, header_data){

							test.equal(status, 400);
							test.deepEqual(header_data,{"Content-Type":"application/json"});
			 		},
			 		end: function( out_str ){

					 		var out_obj = JSON.parse(out_str);
					 		test.deepEqual({jsonrpc:"2.0",err:{code:-32600,message:"Method not found."}, id:"123"},out_obj);

					}
			} , req_str );

	test.done();

}

exports["endpoint.rpc: method invocation: with result, no params"] = function(test){

	var api = {	remote:{
						test: function(ctx, ret_handler){

							ctx.config.save = 0;
							ret_handler(null,{test:1});

						}}
			 };

	var sb = sandbox.require("../lib/sandbox",{
		requires:{"./api":api	}
	});

	var endpoint = sandbox.require("../lib/endpoint",{
		requires:{	"./sandbox":sb,
					"./api":api,
					"./server":{api:{config:{primitives:{test:1}}}}
				}
	});

	var req_str = '{"jsonrpc":"2.0","method":"test","id":123}';

	endpoint.rpc( {writeHead: function(status, header_data){

							test.equal(status, 200);
							test.deepEqual(header_data,{"Content-Type":"application/json"});
			 		},
			 		end: function( out_str ){

					 		var out_obj = JSON.parse(out_str);
					 		test.deepEqual({jsonrpc:"2.0",result:{test:1}, id:"123"},out_obj);
					}
			} , req_str );

	test.done();

}

exports["endpoint.rpc: method invocation: with result, params"] = function(test){

	var req = { "jsonrpc":"2.0",
				"method":"test",
				"params":{x:1,y:2},
				"id":"123"};

	var api = {	remote:{
						test: function(ctx, ret_handler){

							ctx.config.save = 0;
							test.deepEqual(ctx.params, {x:1, y:2, catalog:"docs"});
							ret_handler(null,ctx.params.x + ctx.params.y);

						}}
			 };

	var sb = sandbox.require("../lib/sandbox",{
		requires:{"./api":api}
	});

	var endpoint = sandbox.require("../lib/endpoint",{
		requires:{	"./api":api,
					"./sandbox":sb,
					"./server":{api:{config:{primitives:{test:1}}}}
				}
	});

	var req_str = JSON.stringify(req);

	endpoint.rpc( {writeHead: function(status, header_data){

							test.equal(status, 200);
							test.deepEqual(header_data,{"Content-Type":"application/json"});
			 		},
			 		end: function( out_str ){

					 		var out_obj = JSON.parse(out_str);
					 		test.deepEqual({jsonrpc:"2.0",result:req.params.x + req.params.y, id:"123"},out_obj);
					}
			} , req_str );

	test.done();

}

exports["endpoint.rpc: method invocation: with error"] = function(test){

	var api = {	remote:{
						test: function(ctx, ret_handler){

							ret_handler({code:-1,message:"test error"},null);

						}}
			 };

	var sb = sandbox.require("../lib/sandbox",{
		requires:{"./api":api}
	});

	var endpoint = sandbox.require("../lib/endpoint",{
		requires:{	"./api":api,
					"./sandbox":sb,
					"./server":{api:{config:{primitives:{test:1}}}}
				}
	});

	var req_str = '{"jsonrpc":"2.0","method":"test","id":123}';

	endpoint.rpc( {writeHead: function(status, header_data){

							test.equal(status, 200);
							test.deepEqual(header_data,{"Content-Type":"application/json"});
			 		},
			 		end: function( out_str ){

					 		var out_obj = JSON.parse(out_str);
					 		test.deepEqual({jsonrpc:"2.0",error:{code:-1, message:"test error"}, id:"123"},out_obj);
					}
			} , req_str );

	test.done();

}

exports["endpoint.rpc: method invocation without id"] = function(test){

	var flags = [0, 1, 1, 1];

	var api = {	remote:{
						test: function(ctx, ret_handler){

							flags[0] = 1;	//remote procedure gets executed.
							ctx.config.save = 0;
							ret_handler(null,{});

						}}
			 };

	var sb = sandbox.require("../lib/sandbox",{
		requires:{"./api":api}
	});

	var endpoint = sandbox.require("../lib/endpoint",{
		requires:{	"./api":api,
					"./sandbox":sb,
					"./server":{api:{config:{primitives:{test:1}}}}
				}
	});

	var req_str = '{"jsonrpc":"2.0","method":"test"}';

	endpoint.rpc( {writeHead: function(status, header_data){

					flags[1] = 0; //writeHead() does not get executed (flag not changed).
		 		 },
		 		write: function( out_str ){
		 			flags[2] = 0; //write does not get executed (flag not changed).
		 		},
		 		end: function( out_str ){

		 			flags[3] = 0; //end() does not get executed (flag not changed).
				}
		} , req_str );

	test.ok( flags[0] );
	test.ok( flags[1] );
	test.ok( flags[2] );
	test.ok( flags[3] );
	test.done();

}

exports["endpoint.events: subscribe invocation"] = function(test){

	var endpoint = sandbox.require("../lib/endpoint",{
		requires:{"./evqueue":{	remote:{
								subscribe: function( http_resp, params ){

									test.notEqual( http_resp, undefined);
									test.ok( http_resp.myhttp );
									test.deepEqual(params,{uid:620793114});
								}
							}
		}}
	});

	//json request sent to subscribe to the events channel for uid 620793114
	var req_str = '{"jsonrpc":"2.0","method":"subscribe", "params":{"uid":620793114}}';
	var http_resp = {	myhttp:true,
						writeHead: function(status, header_data){

							test.equal(status,200);
							test.deepEqual(header_data,{"Content-Type":"application/json"});
			 			},
						connection:{
							setTimeout:function(timeout){

								test.equal(timeout,0);
							},
							setNoDelay:function(flag){

								test.ok(flag);
							}
						}
					};

	endpoint.events( http_resp , req_str );

	test.expect(7);
	test.done();
}

<|endoftext|>


<commit_before>import {browserHistory} from 'react-router'
import {routerMiddleware} from 'react-router-redux'
import {applyMiddleware, createStore} from 'redux'
import createLogger from 'redux-logger'

import {middleware as fetch} from '../fetch'
import multi from './multi'
import promise from './promise'

const logger = createLogger({
  collapsed: true,
  duration: true
})

export default function configureStore (initialState, rootReducer) {
  return createStore(
    rootReducer,
    initialState,
    applyMiddleware(
      routerMiddleware(browserHistory),
      fetch,
      multi,
      promise,
      logger
    )
  )
}
<commit_msg>fix(lint): Fix lint error<commit_after>import {browserHistory} from 'react-router'
import {routerMiddleware} from 'react-router-redux'
import {applyMiddleware, createStore} from 'redux'
import createLogger from 'redux-logger'

import {middleware as fetch} from '../fetch'
import multi from './multi'
import promise from './promise'

const logger = createLogger({
  collapsed: true,
  duration: true
})

export default function configureStore (initialState, rootReducer) {
  return createStore(
    rootReducer,
    initialState,
    applyMiddleware(
      routerMiddleware(browserHistory),
      fetch,
      multi,
      promise,
      logger
    )
  )
}
<|endoftext|>


<commit_before>/**
 * Created by rsie on 4/24/2014.
 */
var fs = require('fs')
    ,MongoClient = require('mongodb').MongoClient // Driver for connecting to MongoDB;

describe("Initialize the db to allow other tests to run", function() {
    var boot = fs.readFileSync('./json/bootstrap.json','utf8')
    var config = JSON.parse(boot)
    var theData = fs.readFileSync('./json/register.json','utf8')
    var json = JSON.parse(theData)
    console.log("collection = " + config.register)
    json.data.message.node.nodeId = config.nodeId

    console.log("json = " + json.data.message.node.nodeId)
    it("should connect to mongodb using native driver and save a document needed for getById test",function() {
        MongoClient.connect('mongodb://localhost:27017/'+config.register, function(err, db) {
            if(err) throw err
            db.createCollection(config.register,function(err,collection) {
                collection.remove({"data.message.node.nodeId":json.data.message.node.nodeId},function(err,removed) {
                    console.log("removed: " + removed)
                })
                collection.save(json,function(err,document) {
                    console.log("wrote this doc: " + JSON.stringify(document))
                    db.close()
                })
            })
            expect(json.data.message.node.nodeId).toEqual(config.nodeId)
        })
    })
})
<commit_msg>changed console.log to include the collection that the test data is being saved on.<commit_after>/**
 * Created by rsie on 4/24/2014.
 */
var fs = require('fs')
    ,MongoClient = require('mongodb').MongoClient // Driver for connecting to MongoDB;

describe("Initialize the db to allow other tests to run", function() {
    var boot = fs.readFileSync('./json/bootstrap.json','utf8')
    var config = JSON.parse(boot)
    var theData = fs.readFileSync('./json/register.json','utf8')
    var json = JSON.parse(theData)
    console.log("collection = " + config.register)
    json.data.message.node.nodeId = config.nodeId

    console.log("json = " + json.data.message.node.nodeId)
    it("should connect to mongodb using native driver and save a document needed for getById test",function() {
        MongoClient.connect('mongodb://localhost:27017/'+config.register, function(err, db) {
            if(err) throw err
            db.createCollection(config.register,function(err,collection) {
                collection.remove({"data.message.node.nodeId":json.data.message.node.nodeId},function(err,removed) {
                    console.log("removed: " + removed)
                })
                collection.save(json,function(err,document) {
                    console.log("wrote this doc: " + JSON.stringify(document) + " on collection: " + config.register)
                    db.close()
                })
            })
            expect(json.data.message.node.nodeId).toEqual(config.nodeId)
        })
    })
})
<|endoftext|>