<commit_before>/*
 * yearn Options:
 * {
 *   orgs: {
 *     "org_name": "/absolute/org/location/"
 *   },
 *   logger: "default/log4js",
 *   initialize: "LAZY/LIVELY/OCD",
 *   load_missing: true/false
 *   override: true/false/function( desired )
 * }
 *
 * yearn Examples:
 *   yearn( 'org:module' );
 *   yearn( 'module@version' );
 *   yearn( 'org:module@version' );
 *   yearn( 'module' );
 *   yearn( 'org:module/file' );
 *   yearn( 'module@version/file' );
 *   yearn( 'org:module@version/file' );
 *   yearn( 'module/file' );
 *   yearn( { org: 'org', module: 'module' });
 *   yearn( { module: 'module', version: 'version' });
 *   yearn( { org: 'org', module: 'module', version: 'version' });
 *   yearn( { module: 'module' });
 *   yearn( { org: 'org', module: 'module', file: 'file' });
 *   yearn( { module: 'module', version: 'version', file: 'file' });
 *   yearn( { org: 'org', module: 'module', version: 'version', file: 'file' });
 *   yearn( { module: 'module', file: 'file' });
 */

var semver = require( 'semver' );
var path = require( 'path' );
var fs = require( 'fs' );
var merge = require( 'merge' ).recursive;

var _yearn = null;
var original_resolver = module.constructor._resolveFilename;
var original_require = module.constructor.prototype.require;

function revert( ){
	module.constructor.prototype.require = original_require;
	module.constructor._resolveFilename = original_resolver;
	_yearn = null;
}

module.exports = function( config, force ){

	if( force === true ){
		_yearn = null
	}

	if( _yearn !== null ){
		return _yearn;
	}

	config = require( './utils/config' ).initialize( config );

	var yearn_map = { };
	var package_dependencies = {};
	var yutils = require( './utils/yearn-utils' )( config );

	if( typeof config.override === 'function' ){

		module.constructor.prototype.require = function( desired ){
			return module.constructor._load( desired, this );
		};

		module.constructor._resolveFilename = config.override;

		_yearn = require;
		_yearn.revert = revert;
		_yearn.resolve = require.resolve;
		_yearn._originalResolver = original_resolver;
		return _yearn;
	}

	function populatePackageCache( package_json_location, parent ){
		if( package_dependencies[ package_json_location ] === undefined ){
			yutils.LOGGER.info( 'Importing dependencies from "' + package_json_location + '".' );
			var contents = JSON.parse( fs.readFileSync( package_json_location, 'utf8' ));

			package_dependencies[ package_json_location ] = merge(
				contents.dependencies,
				contents.devDependencies,
				contents.optionalDependencies
			);

			// Creating mapping of module to org
			var reverseOrgs = {};
			Object.keys( package_dependencies[ package_json_location ] ).forEach( function( dependency ){
				dependency = yutils.extractYearningParts( dependency );

				if( dependency.org === undefined )
					dependency.org = '';

				if( reverseOrgs[ dependency.module ] !== undefined && reverseOrgs[ dependency.module ] !== dependency.org ){
					var error = new Error( 'Dependency ' + dependency.module + ' can not exist in multiple orgs [ ' + reverseOrgs[ dependency.module ] + ', ' +  dependency.org + ' ].' );
					yutils.LOGGER.error( error.message );
					throw error;
				}

				reverseOrgs[ dependency.module ] = dependency.org;
			});

			package_dependencies[ package_json_location ].__reverseOrgs = reverseOrgs;
		} else {
			yutils.LOGGER.trace( 'Found cached dependencies of ' + parent.id + '.' );
		}
	}

	function determineYearningPath( desired, parent ){
		var package_json_location = yutils.findPackageJsonLocation( undefined, parent );
		var error = null, module_path = null;

		if( package_json_location === null ){
			error = new Error( 'Failed to find package.json for ' + parent.id + '.' );
			yutils.LOGGER.error( error.message );
			throw error;
		} else {
			populatePackageCache( package_json_location, parent );
		}

		// Determine the org from the package.json if it's not provided (defaults to '').
		if( desired.org === undefined ){
			yutils.LOGGER.debug( 'Determining ' + desired.module + '\'s org from ' + path.resolve( parent.id ) + '\'s package.json' );

			desired.org = package_dependencies[ package_json_location ].__reverseOrgs[ desired.module ];

			// Defaulting to ''.
			if( desired.org === undefined )
				desired.org = '';
		}

		// Determine the version from package.json if it's not provided.
		if( desired.version === undefined ){
			yutils.LOGGER.debug( 'Determining requested version from ' + path.resolve( parent.id ) + '\'s package.json' );

			if( desired.org === '' && package_dependencies[ package_json_location ][ desired.module ] ){
				yutils.LOGGER.debug( 'Resolving version for ' + yutils.constructYearningString( desired )  + '.' );
				desired.version = package_dependencies[ package_json_location ][ desired.module ];
			} else if( desired.org !== '' && package_dependencies[ package_json_location ][ desired.org + config.delimiters.org + desired.module ] ){
				yutils.LOGGER.debug( 'Resolving version for ' + yutils.constructYearningString( desired ) + '.' );
				desired.version = package_dependencies[ package_json_location ][ desired.org + config.delimiters.org + desired.module ];
			} else {
				error = new Error( 'Failed to resolve version from package.json for ' + yutils.constructYearningString( desired )  + '.' );
				yutils.LOGGER.error( error.message );
				throw error;
			}
		}

		// Check that the version is a valid semver.
		if( !yutils.isValidSemVer( desired.version )){
			error = new Error( 'Version must be a valid semver not "' + desired.version + '".');
			yutils.LOGGER.error( error.message );
			throw error;
		}

		// Check the cache's mappings.
		if( yearn_map[ desired.org ] && yearn_map[ desired.org ][ desired.module ] && yearn_map[ desired.org ][ desired.module ][ desired.version ] ){
			yutils.LOGGER.debug(
				'Found cached yearn mapping for "' +
				yutils.constructYearningString( desired ) +
				' -> ' + yearn_map[ desired.org ][ desired.module ][ desired.version ]
			);

			module_path = yearn_map[ desired.org ][ desired.module ][ desired.version ];

			if( desired.file !== undefined )
				module_path = path.join( module_path, desired.file );

			return module_path;
		}

		// Hunt for satisfying module.
		if( config.orgs[ desired.org ] === undefined ){
			error = new Error( 'Org "' + desired.org + '" is not registered with yearn.' );
			yutils.LOGGER.error( error.message );
			throw error;
		}

		var module_location = yutils.findModuleLocation(
			path.resolve( path.dirname( package_json_location ), path.join( config.orgs[ desired.org ] ) ),
			desired.module,
			yutils.isLegacyYearning( desired )
		);

		// Check if the module exists at this level
		if( !fs.existsSync( module_location ) ){
			error = new Error( 'Module "' + desired.module + '" was not found in org "' + desired.org + '".' );
			yutils.LOGGER.error( error.message );
			throw error;

		}

		// Look for "org/module_name/version"
		var available_versions = fs.readdirSync( module_location ).filter( function( version ){
			// Filter out bad versions
			return yutils.isValidSemVer( version );
		}).sort( semver.rcompare );

		for( var index = 0; index < available_versions.length; ++index ){
			if( semver.satisfies( available_versions[ index ], desired.version ) ){
				module_path = path.resolve( path.join( module_location, available_versions[ index ] ));
				if( yearn_map[ desired.org ] === undefined ){
					yearn_map[ desired.org ] = {};
				}

				if( yearn_map[ desired.org ][ desired.module ] === undefined ){
					yearn_map[ desired.org ][ desired.module ] = {};
				}

				yearn_map[ desired.org ][ desired.module ][ desired.version ] = module_path;

				return module_path;
			}
		}

		yutils.LOGGER.warn( 'Unable to find satisfactory version (assuming legacy yearning).' );

		if( desired.file !== undefined )
			module_location = path.join( module_location, desired.file );

		// Fallback to looking for "org/module_name".
		return module_location;
	}

	function yearn( desired, parent ){
		var error = null;

		switch( typeof desired ){
			case 'object':
				yutils.LOGGER.debug( 'Explicit yearning of ' + yutils.constructYearningString( desired ) + '.' );

				if( desired.module === undefined ){
					error = new Error( 'Modern yearn syntax was missing minimum name: ' + JSON.stringify( desired ) + '.' );
					yutils.LOGGER.error( error.message );
					throw error;
				}

				if( desired.org === undefined ){
					desired.org = '';
				}

				break;
			case 'string':
				if( yutils.isNativeModule( desired ) ){
					yutils.LOGGER.info( 'Satiating native yearning for "' + desired + '".' );
					return original_resolver( desired, parent );
				} else if( yutils.isDirectYearning( desired ) ){
					yutils.LOGGER.info( 'Satiating direct yearning for "' + desired + '".' );
					return original_resolver( desired, parent );
				} else {
					yutils.LOGGER.info( 'Implicit yearning for "' + desired + '".' );
					desired = yutils.extractYearningParts( desired );
				}
				break;
			default:
				error = new Error( 'Unrecognized yearn object of type: ' + typeof desired );
				yutils.LOGGER.error( error.message );
				throw error;
		}

		var path = determineYearningPath( desired, parent );

		yutils.LOGGER.info( 'Satiating yearning for "' + yutils.constructYearningString( desired ) + '" with "' + path + '".' );
		return original_resolver( path, parent );
	}

	if( config.override === true ){

		module.constructor.prototype.require = function( desired ){
			return module.constructor._load( desired, this );
		};

		module.constructor._resolveFilename = yearn;

		_yearn = require;
		_yearn.revert = revert;
		_yearn.resolve = require.resolve;
		_yearn._originalResolver = original_resolver;
	} else {

		_yearn = function( desired ){
			var result = yearn( desired, this );
			return module.constructor._load( result, this );
		};

		_yearn.revert = revert;

		_yearn.resolve = function( desired ){
			return yearn( desired, this );
		};

		_yearn._originalResolver = undefined;
	}

	yutils.setLOGGER( config.logger );

	return _yearn;
};

module.exports.ynpm = require( './ynpm' );
<commit_msg>Fixed force JSHint issue<commit_after>/*
 * yearn Options:
 * {
 *   orgs: {
 *     "org_name": "/absolute/org/location/"
 *   },
 *   logger: "default/log4js",
 *   initialize: "LAZY/LIVELY/OCD",
 *   load_missing: true/false
 *   override: true/false/function( desired )
 * }
 *
 * yearn Examples:
 *   yearn( 'org:module' );
 *   yearn( 'module@version' );
 *   yearn( 'org:module@version' );
 *   yearn( 'module' );
 *   yearn( 'org:module/file' );
 *   yearn( 'module@version/file' );
 *   yearn( 'org:module@version/file' );
 *   yearn( 'module/file' );
 *   yearn( { org: 'org', module: 'module' });
 *   yearn( { module: 'module', version: 'version' });
 *   yearn( { org: 'org', module: 'module', version: 'version' });
 *   yearn( { module: 'module' });
 *   yearn( { org: 'org', module: 'module', file: 'file' });
 *   yearn( { module: 'module', version: 'version', file: 'file' });
 *   yearn( { org: 'org', module: 'module', version: 'version', file: 'file' });
 *   yearn( { module: 'module', file: 'file' });
 */

var semver = require( 'semver' );
var path = require( 'path' );
var fs = require( 'fs' );
var merge = require( 'merge' ).recursive;

var _yearn = null;
var original_resolver = module.constructor._resolveFilename;
var original_require = module.constructor.prototype.require;

function revert( ){
	module.constructor.prototype.require = original_require;
	module.constructor._resolveFilename = original_resolver;
	_yearn = null;
}

module.exports = function( config, force ){

	if( force === true ){
		_yearn = null;
	}

	if( _yearn !== null ){
		return _yearn;
	}

	config = require( './utils/config' ).initialize( config );

	var yearn_map = { };
	var package_dependencies = {};
	var yutils = require( './utils/yearn-utils' )( config );

	if( typeof config.override === 'function' ){

		module.constructor.prototype.require = function( desired ){
			return module.constructor._load( desired, this );
		};

		module.constructor._resolveFilename = config.override;

		_yearn = require;
		_yearn.revert = revert;
		_yearn.resolve = require.resolve;
		_yearn._originalResolver = original_resolver;
		return _yearn;
	}

	function populatePackageCache( package_json_location, parent ){
		if( package_dependencies[ package_json_location ] === undefined ){
			yutils.LOGGER.info( 'Importing dependencies from "' + package_json_location + '".' );
			var contents = JSON.parse( fs.readFileSync( package_json_location, 'utf8' ));

			package_dependencies[ package_json_location ] = merge(
				contents.dependencies,
				contents.devDependencies,
				contents.optionalDependencies
			);

			// Creating mapping of module to org
			var reverseOrgs = {};
			Object.keys( package_dependencies[ package_json_location ] ).forEach( function( dependency ){
				dependency = yutils.extractYearningParts( dependency );

				if( dependency.org === undefined )
					dependency.org = '';

				if( reverseOrgs[ dependency.module ] !== undefined && reverseOrgs[ dependency.module ] !== dependency.org ){
					var error = new Error( 'Dependency ' + dependency.module + ' can not exist in multiple orgs [ ' + reverseOrgs[ dependency.module ] + ', ' +  dependency.org + ' ].' );
					yutils.LOGGER.error( error.message );
					throw error;
				}

				reverseOrgs[ dependency.module ] = dependency.org;
			});

			package_dependencies[ package_json_location ].__reverseOrgs = reverseOrgs;
		} else {
			yutils.LOGGER.trace( 'Found cached dependencies of ' + parent.id + '.' );
		}
	}

	function determineYearningPath( desired, parent ){
		var package_json_location = yutils.findPackageJsonLocation( undefined, parent );
		var error = null, module_path = null;

		if( package_json_location === null ){
			error = new Error( 'Failed to find package.json for ' + parent.id + '.' );
			yutils.LOGGER.error( error.message );
			throw error;
		} else {
			populatePackageCache( package_json_location, parent );
		}

		// Determine the org from the package.json if it's not provided (defaults to '').
		if( desired.org === undefined ){
			yutils.LOGGER.debug( 'Determining ' + desired.module + '\'s org from ' + path.resolve( parent.id ) + '\'s package.json' );

			desired.org = package_dependencies[ package_json_location ].__reverseOrgs[ desired.module ];

			// Defaulting to ''.
			if( desired.org === undefined )
				desired.org = '';
		}

		// Determine the version from package.json if it's not provided.
		if( desired.version === undefined ){
			yutils.LOGGER.debug( 'Determining requested version from ' + path.resolve( parent.id ) + '\'s package.json' );

			if( desired.org === '' && package_dependencies[ package_json_location ][ desired.module ] ){
				yutils.LOGGER.debug( 'Resolving version for ' + yutils.constructYearningString( desired )  + '.' );
				desired.version = package_dependencies[ package_json_location ][ desired.module ];
			} else if( desired.org !== '' && package_dependencies[ package_json_location ][ desired.org + config.delimiters.org + desired.module ] ){
				yutils.LOGGER.debug( 'Resolving version for ' + yutils.constructYearningString( desired ) + '.' );
				desired.version = package_dependencies[ package_json_location ][ desired.org + config.delimiters.org + desired.module ];
			} else {
				error = new Error( 'Failed to resolve version from package.json for ' + yutils.constructYearningString( desired )  + '.' );
				yutils.LOGGER.error( error.message );
				throw error;
			}
		}

		// Check that the version is a valid semver.
		if( !yutils.isValidSemVer( desired.version )){
			error = new Error( 'Version must be a valid semver not "' + desired.version + '".');
			yutils.LOGGER.error( error.message );
			throw error;
		}

		// Check the cache's mappings.
		if( yearn_map[ desired.org ] && yearn_map[ desired.org ][ desired.module ] && yearn_map[ desired.org ][ desired.module ][ desired.version ] ){
			yutils.LOGGER.debug(
				'Found cached yearn mapping for "' +
				yutils.constructYearningString( desired ) +
				' -> ' + yearn_map[ desired.org ][ desired.module ][ desired.version ]
			);

			module_path = yearn_map[ desired.org ][ desired.module ][ desired.version ];

			if( desired.file !== undefined )
				module_path = path.join( module_path, desired.file );

			return module_path;
		}

		// Hunt for satisfying module.
		if( config.orgs[ desired.org ] === undefined ){
			error = new Error( 'Org "' + desired.org + '" is not registered with yearn.' );
			yutils.LOGGER.error( error.message );
			throw error;
		}

		var module_location = yutils.findModuleLocation(
			path.resolve( path.dirname( package_json_location ), path.join( config.orgs[ desired.org ] ) ),
			desired.module,
			yutils.isLegacyYearning( desired )
		);

		// Check if the module exists at this level
		if( !fs.existsSync( module_location ) ){
			error = new Error( 'Module "' + desired.module + '" was not found in org "' + desired.org + '".' );
			yutils.LOGGER.error( error.message );
			throw error;

		}

		// Look for "org/module_name/version"
		var available_versions = fs.readdirSync( module_location ).filter( function( version ){
			// Filter out bad versions
			return yutils.isValidSemVer( version );
		}).sort( semver.rcompare );

		for( var index = 0; index < available_versions.length; ++index ){
			if( semver.satisfies( available_versions[ index ], desired.version ) ){
				module_path = path.resolve( path.join( module_location, available_versions[ index ] ));
				if( yearn_map[ desired.org ] === undefined ){
					yearn_map[ desired.org ] = {};
				}

				if( yearn_map[ desired.org ][ desired.module ] === undefined ){
					yearn_map[ desired.org ][ desired.module ] = {};
				}

				yearn_map[ desired.org ][ desired.module ][ desired.version ] = module_path;

				return module_path;
			}
		}

		yutils.LOGGER.warn( 'Unable to find satisfactory version (assuming legacy yearning).' );

		if( desired.file !== undefined )
			module_location = path.join( module_location, desired.file );

		// Fallback to looking for "org/module_name".
		return module_location;
	}

	function yearn( desired, parent ){
		var error = null;

		switch( typeof desired ){
			case 'object':
				yutils.LOGGER.debug( 'Explicit yearning of ' + yutils.constructYearningString( desired ) + '.' );

				if( desired.module === undefined ){
					error = new Error( 'Modern yearn syntax was missing minimum name: ' + JSON.stringify( desired ) + '.' );
					yutils.LOGGER.error( error.message );
					throw error;
				}

				if( desired.org === undefined ){
					desired.org = '';
				}

				break;
			case 'string':
				if( yutils.isNativeModule( desired ) ){
					yutils.LOGGER.info( 'Satiating native yearning for "' + desired + '".' );
					return original_resolver( desired, parent );
				} else if( yutils.isDirectYearning( desired ) ){
					yutils.LOGGER.info( 'Satiating direct yearning for "' + desired + '".' );
					return original_resolver( desired, parent );
				} else {
					yutils.LOGGER.info( 'Implicit yearning for "' + desired + '".' );
					desired = yutils.extractYearningParts( desired );
				}
				break;
			default:
				error = new Error( 'Unrecognized yearn object of type: ' + typeof desired );
				yutils.LOGGER.error( error.message );
				throw error;
		}

		var path = determineYearningPath( desired, parent );

		yutils.LOGGER.info( 'Satiating yearning for "' + yutils.constructYearningString( desired ) + '" with "' + path + '".' );
		return original_resolver( path, parent );
	}

	if( config.override === true ){

		module.constructor.prototype.require = function( desired ){
			return module.constructor._load( desired, this );
		};

		module.constructor._resolveFilename = yearn;

		_yearn = require;
		_yearn.revert = revert;
		_yearn.resolve = require.resolve;
		_yearn._originalResolver = original_resolver;
	} else {

		_yearn = function( desired ){
			var result = yearn( desired, this );
			return module.constructor._load( result, this );
		};

		_yearn.revert = revert;

		_yearn.resolve = function( desired ){
			return yearn( desired, this );
		};

		_yearn._originalResolver = undefined;
	}

	yutils.setLOGGER( config.logger );

	return _yearn;
};

module.exports.ynpm = require( './ynpm' );
<|endoftext|>


<commit_before>var app = require('../server'),
    request = require('supertest');

describe('Valid app', function() {
    const agent = request.agent(app);
    let id;
    it('connects to server', function(){
        agent.post('/users/register/toto/').end(function(err, res) {
			expect(true).toBe(false);
            expect(err).toBeNull();
            id = res.body.id;
            expect(id).not.toBeUndefined();
			done()
        })
    })

    it('joins a channel', function() {
        agent.put('/user/' + id + '/channels/channel-1/join/')
            .end(function(err, res) {
                expect(err).toBeNull();
                const user = res.body.user;
                expect(user).not.toBeNull();
                expect(user.id).toEqual(id);
				done()
            })
    })

    it('talks in channel', function() {
        agent.put('/user/' + id + '/channels/channel-1/say/')
            .send({ message: 'Hello, world!' })
            .end(function(err, res) {
                expect(err).toBeNull()
                const user = res.body.user;
                expect(user).not.toBeNull();
                expect(user.id).toEqual(id);
				done()
            })
    })

    it('checks for notices', function() {
        agent.put('/user/' + id + '/notices/')
            .end(function(err, res) {
                expect(err).toBeNull()
                const notices = res.body.notices
                expect(notices).not.toBeNull()
                expect(notices.length).toEqual(2)
                expect(notices[0]['type']).toEqual('channelJoin');
                expect(notices[0]['nick']).toEqual('toto');
                expect(notices[0]['channel']).toEqual('channel-1');

                expect(notices[1]['type']).toEqual('channelMessage');
                expect(notices[1]['nick']).toEqual('toto');
                expect(notices[1]['channel']).toEqual('channel-1');
				done()
            })
    })

    it('disconnects', function() {
        agent.put('/user/' + id + '/disconnect/')
            .end(function(err, res) {
                expect(err).toBeNull()
                const version = res.body.version
                expect(version).not.toBeNull()
				done()
            })
    })
});

describe('Invalid app', function() {
    // TODO Invalid actions
})
<commit_msg>Added done parameter<commit_after>var app = require('../server'),
    request = require('supertest');

describe('Valid app', function() {
    const agent = request.agent(app);
    let id;
    it('connects to server', function(done){
        agent.post('/users/register/toto/')
		.end(function(err, res) {
				expect(true).toBe(false);
				expect(err).toBeNull();
				id = res.body.id;
				expect(id).not.toBeUndefined();
				done()
			})
    })

    it('joins a channel', function(done) {
        agent.put('/user/' + id + '/channels/channel-1/join/')
            .end(function(err, res) {
                expect(err).toBeNull();
                const user = res.body.user;
                expect(user).not.toBeNull();
                expect(user.id).toEqual(id);
				done()
            })
    })

    it('talks in channel', function(done) {
        agent.put('/user/' + id + '/channels/channel-1/say/')
            .send({ message: 'Hello, world!' })
            .end(function(err, res) {
                expect(err).toBeNull()
                const user = res.body.user;
                expect(user).not.toBeNull();
                expect(user.id).toEqual(id);
				done()
            })
    })

    it('checks for notices', function(done) {
        agent.put('/user/' + id + '/notices/')
            .end(function(err, res) {
                expect(err).toBeNull()
                const notices = res.body.notices
                expect(notices).not.toBeNull()
                expect(notices.length).toEqual(2)
                expect(notices[0]['type']).toEqual('channelJoin');
                expect(notices[0]['nick']).toEqual('toto');
                expect(notices[0]['channel']).toEqual('channel-1');

                expect(notices[1]['type']).toEqual('channelMessage');
                expect(notices[1]['nick']).toEqual('toto');
                expect(notices[1]['channel']).toEqual('channel-1');
				done()
            })
    })

    it('disconnects', function(done) {
        agent.put('/user/' + id + '/disconnect/')
            .end(function(err, res) {
                expect(err).toBeNull()
                const version = res.body.version
                expect(version).not.toBeNull()
				done()
            })
    })
});

describe('Invalid app', function() {
    // TODO Invalid actions
})
<|endoftext|>


<commit_before>/************************************************************
 *
 * Server
 *
 ***********************************************************/
require('mootools');

var Express = require('express');
var Program = require('commander');
var Http = require('http');
var Path = require('path');
var Fs = require('fs');
var SocketIo = require('socket.io');
var MongoClient = require('mongodb').MongoClient;
var ObjectID = require('mongodb').ObjectID;

var Console = require('./Console');
var Instagram = require('./Instagram');
var Routes = require('./Routes');

var Server = new Class({

  Implements: [Options]

  // Options
  ,options: {
  }

  // Constructor
  // --------------------------------------------------------
  ,initialize: function() {

    // Process args
    this.args = Program
      .version('0.0.1')
      .option('-s, --settings [path]', 'Start with custom settings file')
      .option('-n, --nopolling', 'Start without media polling')
      .option('-d, --debug', 'Force debug console output')
      .parse(process.argv);

    var file = './settings.json';

    if(Program.settings) {
      file = Path.normalize(process.cwd() + '/' + Program.settings);
    }

    // Check if file exists...
    if(Fs.existsSync(file)) {

      // Include project file
      var settings = require(file);

      // Debug
      Console.DEBUG = settings.debug;
      if(Program.debug) { Console.DEBUG = true; }

      Console.status('Started with settings ' + file);

      // Set options
      this.setOptions(settings);

      // Connect mongo db
      this.connectDb();

    } else {

      // No file found
      Console.error('Could not find settings file at ' + file);
      process.exit(0);
    }

  }

  // Connect to mongodb
  // --------------------------------------------------------
  ,connectDb: function() {

    var self = this;

    MongoClient.connect(

      'mongodb://'
      + this.options.mongodb.username
      + ':'
      + this.options.mongodb.password
      + '@'
      + this.options.mongodb.host
      + ':' + this.options.mongodb.port
      + '/' + this.options.mongodb.db

      ,function(err, db) {

        if(err) {
          Console.error('Could not connect to DB');
          process.exit(0);
        }

        Console.info('MongoDb connected');

        self.db = db;

        // Setup server
        self.setupServer();

        // Setup Instagram api
        self.setupInstagramApi();
      }

    );
  }

  // Setup http server and socket.io
  // --------------------------------------------------------
  ,setupServer: function() {

    // Create expressjs app
    this.app = Express();

    // Setup http server
    this.server = Http.Server(this.app);

    // Setup socket io
    //this.socket = new SocketIo(this.server);

    // Tag subscription router
    //this.tagSubscriptionRouter = new Routes.TagSubscription(this);
    //this.app.use(this.tagSubscriptionRouter.router);

    // Admin router
    this.adminRouter = new Routes.Admin(this);
    this.app.use(this.adminRouter.router);

    // Images router
    this.imagesRouter = new Routes.Images(this);
    this.app.use(this.imagesRouter.router);

    // Start http server
    this.server.listen(this.options.http.port);

    Console.info('Server started');

  }

  // Setup Instagram API
  // --------------------------------------------------------
  ,setupInstagramApi: function() {

    var self = this;

    // Create Instagram api
    this.instagram = new Instagram({

      client_id: this.options.instagram.client_id
      ,client_secret: this.options.instagram.client_secret
    });

    // Get recent media
    if(!Program.nopolling) {

      // Get recent tag media
      self.options.instagram.hashtags.each(function(tag, i) {
        self.getTagRecentMedia(tag);
      });
    }

  }

  // Get recent media
  // --------------------------------------------------------
  ,getTagRecentMedia: function(tag) {

    var self = this;

    // Get recent media for tag callback
    var rm_callback = function(err, medias, pagination, remaining, limit) {

      // Retry after x seconds
      // if media is not updated or
      // failed to return any images
      var retry = function() {

        setTimeout(function() {
          var opt = {};

          if(pagination) {
            if(pagination.min_tag_id) {
              var opt = {
                min_tag_id: pagination.min_tag_id
              };
            }
          }

          self.instagram.getTagRecentMedia(tag, opt, rm_callback);
        }, self.options.instagram.request_delay);
      }

      // 503 error
      if(err) {

        // Check for 503 status code
        if(err.status_code == 503) {
          Console.error('503 Service Unavailable. No server is available to handle this request.');
        } else {
          Console.error('Get recent media request failed.');
        }

        // Retry after x seconds
        retry();

        return;
      }

      Console.status('Received recent media for tag ' + tag);
      Console.status(remaining + ' remaining calls');

      // Empty check
      if(medias) {

        var collection = self.db.collection('instagram');

        // Fill new array with all media
        var new_medias = new Array();

        // Iterator
        var next_media = function(list, callback) {

          if(list.length == 0) {
            callback();
            return;
          }

          var media = list.pop();

          // Check for image type and existing id
          if((media.type == 'image' && media.id)) {

            // Check if media already exists
            var exists = collection.find({media_id: media.id}).limit(1);

            exists.count(function(err, count) {

              // If media doesn't exist
              if(count==0) {

                // Check type (tag or user)
		            var mtype = (self.options.instagram.users.indexOf(media.user.username) < 0) ? 'tag' : 'user';

                // Create media object
                new_medias.push({

                  media_id: media.id
                  ,msg_type: mtype
                  ,queue_id: ObjectID()
                  ,images: media.images
                  ,user: media.user
                  ,filter: media.filter
                  ,tags: media.tags
                  ,link: media.link
                  ,likes: media.likes.count
                  ,location: media.location
                  ,created_time: parseInt(media.created_time)
                  ,modified_time: Date.now()
                  ,locked_time: Date.now()
                  ,locked: false
                  ,approved: (mtype == 'user' && self.options.instagram.auto_approve_users)
                  ,reviewed: false
                });
              }

              setTimeout(function() {
                next_media(list, callback);
              }, 100);

            });
          } else {
            setTimeout(function() {
              next_media(list, callback);
            }, 100);
          }
        };

        // Check all media and add to db
        // if media does not exist
        next_media(Array.clone(medias), function() {

          if(new_medias.length > 0) {

            // New images added
            Console.status(new_medias.length + ' images added for tag ' + tag);

            collection.insert(new_medias, {w:1}, function(err, result) {

              if(err) throw err;

              // Call next page if pagination
              // is available
              if(pagination) {
                if(pagination.next) {
                  setTimeout(function() {
                    pagination.next(rm_callback);
                  }, self.options.instagram.request_delay);
                } else {
                  retry();
                }
              } else {
                retry();
              }
            });

            if(pagination.next) {
              setTimeout(function() {
                pagination.next(rm_callback);
              }, self.options.instagram.request_delay);
            } else {
              retry();
            }
          // No new images found..
          } else {
            Console.status('No new images found for tag ' + tag);
            retry();
          }
        });
      } else {
        retry();
      }
    }

    // Get recent media for tag
    this.instagram.getTagRecentMedia(tag, {}, rm_callback);
  }

});

// Start server
Server = new Server();
<commit_msg>mongo tests<commit_after>/************************************************************
 *
 * Server
 *
 ***********************************************************/
require('mootools');

var Express = require('express');
var Program = require('commander');
var Http = require('http');
var Path = require('path');
var Fs = require('fs');
var SocketIo = require('socket.io');
var MongoClient = require('mongodb').MongoClient;
var ObjectID = require('mongodb').ObjectID;

var Console = require('./Console');
var Instagram = require('./Instagram');
var Routes = require('./Routes');

var Server = new Class({

  Implements: [Options]

  // Options
  ,options: {
  }

  // Constructor
  // --------------------------------------------------------
  ,initialize: function() {

    // Process args
    this.args = Program
      .version('0.0.1')
      .option('-s, --settings [path]', 'Start with custom settings file')
      .option('-n, --nopolling', 'Start without media polling')
      .option('-d, --debug', 'Force debug console output')
      .parse(process.argv);

    var file = './settings.json';

    if(Program.settings) {
      file = Path.normalize(process.cwd() + '/' + Program.settings);
    }

    // Check if file exists...
    if(Fs.existsSync(file)) {

      // Include project file
      var settings = require(file);

      // Debug
      Console.DEBUG = settings.debug;
      if(Program.debug) { Console.DEBUG = true; }

      Console.status('Started with settings ' + file);

      // Set options
      this.setOptions(settings);

      // Connect mongo db
      this.connectDb();

    } else {

      // No file found
      Console.error('Could not find settings file at ' + file);
      process.exit(0);
    }

  }

  // Connect to mongodb
  // --------------------------------------------------------
  ,connectDb: function() {

    var self = this;

    MongoClient.connect(

      'mongodb://'
      + this.options.mongodb.username
      + ':'
      + this.options.mongodb.password
      + '@'
      + this.options.mongodb.host
      + ':' + this.options.mongodb.port
      + '/' + this.options.mongodb.db

      ,function(err, db) {

        if(err) {
          Console.error('Could not connect to DB');
          process.exit(0);
        }

        Console.info('MongoDb connected');

        self.db = db;

        // Setup server
        self.setupServer();

        // Setup Instagram api
        self.setupInstagramApi();
      }

    );
  }

  // Setup http server and socket.io
  // --------------------------------------------------------
  ,setupServer: function() {

    // Create expressjs app
    this.app = Express();

    // Setup http server
    this.server = Http.Server(this.app);

    // Setup socket io
    //this.socket = new SocketIo(this.server);

    // Tag subscription router
    //this.tagSubscriptionRouter = new Routes.TagSubscription(this);
    //this.app.use(this.tagSubscriptionRouter.router);

    // Admin router
    this.adminRouter = new Routes.Admin(this);
    this.app.use(this.adminRouter.router);

    // Images router
    this.imagesRouter = new Routes.Images(this);
    this.app.use(this.imagesRouter.router);

    // Start http server
    this.server.listen(this.options.http.port);

    Console.info('Server started');

  }

  // Setup Instagram API
  // --------------------------------------------------------
  ,setupInstagramApi: function() {

    var self = this;

    // Create Instagram api
    this.instagram = new Instagram({

      client_id: this.options.instagram.client_id
      ,client_secret: this.options.instagram.client_secret
    });

    // Get recent media
    if(!Program.nopolling) {

      // Get recent tag media
      self.options.instagram.hashtags.each(function(tag, i) {
        self.getTagRecentMedia(tag);
      });
    }

  }

  // Get recent media
  // --------------------------------------------------------
  ,getTagRecentMedia: function(tag) {

    var self = this;

    // Get recent media for tag callback
    var rm_callback = function(err, medias, pagination, remaining, limit) {

      // Retry after x seconds
      // if media is not updated or
      // failed to return any images
      var retry = function() {

        setTimeout(function() {
          var opt = {};

          if(pagination) {
            if(pagination.min_tag_id) {
              var opt = {
                min_tag_id: pagination.min_tag_id
              };
            }
          }

          self.instagram.getTagRecentMedia(tag, opt, rm_callback);
        }, self.options.instagram.request_delay);
      }

      // 503 error
      if(err) {

        // Check for 503 status code
        if(err.status_code == 503) {
          Console.error('503 Service Unavailable. No server is available to handle this request.');
        } else {
          Console.error('Get recent media request failed.');
        }

        // Retry after x seconds
        retry();

        return;
      }

      Console.status('Received recent media for tag ' + tag);
      Console.status(remaining + ' remaining calls');

      // Empty check
      if(medias) {

        var collection = self.db.collection('instagram');

        // Fill new array with all media
        var new_medias = new Array();

        // Iterator
        var next_media = function(list, callback) {

          if(list.length == 0) {
            callback();
            return;
          }

          var media = list.pop();

          // Check for image type and existing id
          if((media.type == 'image' && media.id)) {

            // Check if media already exists
            var exists = collection.find({media_id: media.id}, {hint:{media_id:1}}).limit(1);

            exists.count(function(err, count) {

              // If media doesn't exist
              if(count==0) {

                // Check type (tag or user)
		            var mtype = (self.options.instagram.users.indexOf(media.user.username) < 0) ? 'tag' : 'user';

                // Create media object
                new_medias.push({

                  media_id: media.id
                  ,msg_type: mtype
                  ,queue_id: ObjectID()
                  ,images: media.images
                  ,user: media.user
                  ,filter: media.filter
                  ,tags: media.tags
                  ,link: media.link
                  ,likes: media.likes.count
                  ,location: media.location
                  ,created_time: parseInt(media.created_time)
                  ,modified_time: Date.now()
                  ,locked_time: Date.now()
                  ,locked: false
                  ,approved: (mtype == 'user' && self.options.instagram.auto_approve_users)
                  ,reviewed: false
                });
              }

              next_media(list, callback);

            });
          } else {

            next_media(list, callback);
          }
        };

        // Check all media and add to db
        // if media does not exist
        next_media(Array.clone(medias), function() {

          if(new_medias.length > 0) {

            // New images added
            Console.status(new_medias.length + ' images added for tag ' + tag);

            collection.insert(new_medias, {w:1}, function(err, result) {

              if(err) throw err;

              // Call next page if pagination
              // is available
              if(pagination) {
                if(pagination.next) {
                  setTimeout(function() {
                    pagination.next(rm_callback);
                  }, self.options.instagram.request_delay);
                } else {
                  retry();
                }
              } else {
                retry();
              }
            });

            if(pagination.next) {
              setTimeout(function() {
                pagination.next(rm_callback);
              }, self.options.instagram.request_delay);
            } else {
              retry();
            }
          // No new images found..
          } else {
            Console.status('No new images found for tag ' + tag);
            retry();
          }
        });
      } else {
        retry();
      }
    }

    // Get recent media for tag
    this.instagram.getTagRecentMedia(tag, {}, rm_callback);
  }

});

// Start server
Server = new Server();
<|endoftext|>


<commit_before>class APIDocumentation {
  static _markdownToDOM(markdownText) {
    const reader = new commonmark.Parser();
    const ast = reader.parse(markdownText);
    const writer = new commonmark.HtmlRenderer();
    const result = writer.render(ast);
    const domParser = new DOMParser();
    return document.importNode(domParser.parseFromString(result, 'text/html').body, true);
  }
  /**
   * @param {string} version
   * @param {string} releaseNotes
   * @param {string} markdownText
   */
  static create(version, releaseNotes, markdownText) {
    // Parse markdown into HTML
    const doc = APIDocumentation._markdownToDOM(markdownText);

    // Translate all relative links to ppdoc links.
    for (const anchor of doc.querySelectorAll('a')) {
      const href = anchor.getAttribute('href') || '';
      if (href.startsWith('#')) {
        // Link referencing other part of documentation.
        const githubAnchor = href.substring(1);
        const entryId = APIDocumentation._idFromGHAnchor(githubAnchor);
        anchor.setAttribute('href', app.linkURL(version, entryId));
      } else if (href.startsWith('/') || href.startsWith('../') || href.startsWith('./')) {
        // Link pointing somewhere to PPTR repository.
        const isRelease = /^\d+\.\d+\.\d+$/.test(version);
        const branch = isRelease ? 'v' + version : 'master';
        anchor.setAttribute('href', `https://github.com/GoogleChrome/puppeteer/blob/${branch}/docs/${href}`);
      }
      // Mark link as external if necessary
      if (anchor.hostname !== location.hostname && anchor.hostname.length)
        anchor.appendChild(document.createElement('external-link-icon'));
    }

    // Highlight all code blocks.
    for (const code of doc.querySelectorAll('code.language-js'))
      CodeMirror.runMode(code.textContent, 'text/javascript', code);

    const api = new APIDocumentation(version);

    // Add release notes if we have any.
    if (releaseNotes) {
      api.sections.push(APISection.create(api, 'Release Notes', APIDocumentation._markdownToDOM(releaseNotes)));
    }

    // All class headers are rendered as H3 tags
    const headers = doc.querySelectorAll('h3');
    for (let i = 0; i < headers.length; ++i) {
      const header = headers[i];
      const nextHeader = i + 1 < headers.length ? headers[i + 1] : null;
      const title = header.textContent;
      // Import all HTML from section until we hit next top-level header.
      const content = extractSiblingsIntoFragment(header.nextSibling, nextHeader);
      if (title.toLowerCase().startsWith('class:'))
        api.classes.push(APIClass.create(api, title, content));
      else
        api.sections.push(APISection.create(api, title, content));
    }
    api._initialize();
    return api;
  }

  static _idFromGHAnchor(githubAnchor) {
    return 'api-' + githubAnchor;
  }

  constructor(version) {
    this.version = version;
    this.sections = [];
    this.classes = [];

    this._defaultContentId = null;
    this._idToEntry = new Map();
  }

  defaultContentId() {
    return this._defaultContentId;
  }

  _initialize() {
    const generateGithubAnchor = (title) => {
      const id = title.trim().toLowerCase().replace(/\s/g, '-').replace(/[^-0-9a-zа-яё]/ig, '');
      let dedupId = id;
      let counter = 0;
      while (this._idToEntry.has(dedupId))
        dedupId = id + '-' + (++counter);
      return dedupId;
    }

    const assignId = (entry, title) => {
      const contentId = APIDocumentation._idFromGHAnchor(generateGithubAnchor(title));
      entry.contentId = contentId;
      this._idToEntry.set(contentId, entry);
    };

    for (const section of this.sections)
      assignId(section, section.name);
    for (const apiClass of this.classes) {
      assignId(apiClass, `class: '${apiClass.name}'`);
      for (const apiEvent of apiClass.events)
        assignId(apiEvent, `event: '${apiEvent.name}'`);
      for (const apiMethod of apiClass.methods)
        assignId(apiMethod, `${apiClass.loweredName}.${apiMethod.name}(${apiMethod.args})`);
      for (const ns of apiClass.namespaces)
        assignId(ns, `${apiClass.loweredName}.${ns.name}`);
    }

    this._defaultContentId = this._idToEntry.keys().next().value;
  }

  idToEntry(id) {
    return this._idToEntry.get(id) || null;
  }
}

class APIEntry {
  constructor(api, name, element, contentId) {
    this.api = api;
    this.name = name;
    this.element = element;
    // This has to be assigned later.
    this.contentId = null;
  }

  linkURL() {
    return app.linkURL(this.api.version, this.contentId);
  }
}

class APISection extends APIEntry {
  static create(api, title, descFragment) {
    const element = document.createElement('api-section');
    element.classList.add('api-entry');
    element.innerHTML = `<h1>${title}</h1>`;
    element.appendChild(descFragment);
    return new APISection(api, title, element);
  }

  constructor(api, name, element) {
    super(api, name, element);
  }
}

class APIClass extends APIEntry {
  static create(api, title, fragment) {
    const name = title.replace(/^class:/i, '').trim();
    const headers = fragment.querySelectorAll('h4');

    const element = document.createElement('api-class');
    element.classList.add('api-entry');
    element.innerHTML = `<h3><pptr-class-icon></pptr-class-icon><api-class-name>class: ${name}</api-class-name></h3>`;
    element.appendChild(extractSiblingsIntoFragment(fragment.firstChild, headers[0]));
    const apiClass = new APIClass(api, name, element);

    for (let i = 0; i < headers.length; ++i) {
      const header = headers[i];
      const nextHeader = i + 1 < headers.length ? headers[i + 1] : null;
      const title = header.textContent;
      const fragment = extractSiblingsIntoFragment(header.nextSibling, nextHeader);
      if (title.toLowerCase().startsWith('event:'))
        apiClass.events.push(APIEvent.create(apiClass, title, fragment));
      else if (title.includes('('))
        apiClass.methods.push(APIMethod.create(apiClass, title, fragment));
      else
        apiClass.namespaces.push(APINamespace.create(apiClass, title, fragment));
    }
    return apiClass;
  }

  constructor(api, name, element) {
    super(api, name, element);
    this.loweredName = name.substring(0, 1).toLowerCase() + name.substring(1);
    this.methods = [];
    this.events = [];
    this.namespaces = [];
  }
}

class APINamespace extends APIEntry {
  static create(apiClass, title, fragment) {
    const name = title.split('.').pop();
    const element = document.createElement('api-ns');
    element.classList.add('api-entry');
    element.innerHTML = [
      `<h4>`,
        '<pptr-ns-icon></pptr-ns-icon>',
        `<api-ns-classname>${apiClass.loweredName}</api-ns-classname>`,
        `<api-ns-name>.${name}</api-ns-name>`,
      `</h4>`
    ].join('');
    element.appendChild(fragment);
    return new APINamespace(apiClass, name, element);
  }

  constructor(apiClass, name, element) {
    super(apiClass.api, name, element);
    this.apiClass = apiClass;
  }
}

class APIMethod extends APIEntry {
  static create(apiClass, title, descFragment) {
    const name = title.match(/\.([^(]*)/)[1];
    const args = title.match(/\((.*)\)/)[1];
    const element = document.createElement('api-method');
    element.classList.add('api-entry');
    element.innerHTML = [
      `

        <pptr-method-icon></pptr-method-icon>
        <api-method-classname>${apiClass.loweredName}</api-method-classname>`,
        `<api-method-name>.${name}</api-method-name>`,
        `<api-method-args>(${args})</api-method-args>`,
      `</h4>`
    ].join('');
    element.appendChild(descFragment);
    return new APIMethod(apiClass, name, args, element);
  }

  constructor(apiClass, name, args, element) {
    super(apiClass.api, name, element);
    this.apiClass = apiClass;
    this.args = args;
  }
}

class APIEvent extends APIEntry {
  static create(apiClass, title, descFragment) {
    const name = title.match(/'(.*)'/)[1];
    const element = document.createElement('api-event');
    element.classList.add('api-entry');
    element.innerHTML = `<h4><pptr-event-icon></pptr-event-icon>${apiClass.loweredName}.on(<api-event-name>'${name}'</api-event-name>)</h4>`;
    element.appendChild(descFragment);
    return new APIEvent(apiClass, name, element);
  }

  constructor(apiClass, name, element) {
    super(apiClass.api, name, element);
    this.apiClass = apiClass;
  }
}

/**
 * @param {!Node} fromInclusive
 * @param {!Node} toExclusive
 * @return {!DocumentFragment}
 */
function extractSiblingsIntoFragment(fromInclusive, toExclusive) {
  const fragment = document.createDocumentFragment();
  let node = fromInclusive;
  while (node && node !== toExclusive) {
    const next = node.nextSibling;
    fragment.appendChild(node);
    node = next;
  }
  return fragment;
}

<commit_msg>feature: generate outline for classes<commit_after>class APIDocumentation {
  static _markdownToDOM(markdownText) {
    const reader = new commonmark.Parser();
    const ast = reader.parse(markdownText);
    const writer = new commonmark.HtmlRenderer();
    const result = writer.render(ast);
    const domParser = new DOMParser();
    return document.importNode(domParser.parseFromString(result, 'text/html').body, true);
  }
  /**
   * @param {string} version
   * @param {string} releaseNotes
   * @param {string} markdownText
   */
  static create(version, releaseNotes, markdownText) {
    // Parse markdown into HTML
    const doc = APIDocumentation._markdownToDOM(markdownText);

    // Translate all relative links to ppdoc links.
    for (const anchor of doc.querySelectorAll('a')) {
      const href = anchor.getAttribute('href') || '';
      if (href.startsWith('#')) {
        // Link referencing other part of documentation.
        const githubAnchor = href.substring(1);
        const entryId = APIDocumentation._idFromGHAnchor(githubAnchor);
        anchor.setAttribute('href', app.linkURL(version, entryId));
      } else if (href.startsWith('/') || href.startsWith('../') || href.startsWith('./')) {
        // Link pointing somewhere to PPTR repository.
        const isRelease = /^\d+\.\d+\.\d+$/.test(version);
        const branch = isRelease ? 'v' + version : 'master';
        anchor.setAttribute('href', `https://github.com/GoogleChrome/puppeteer/blob/${branch}/docs/${href}`);
      }
      // Mark link as external if necessary
      if (anchor.hostname !== location.hostname && anchor.hostname.length)
        anchor.appendChild(document.createElement('external-link-icon'));
    }

    // Highlight all code blocks.
    for (const code of doc.querySelectorAll('code.language-js'))
      CodeMirror.runMode(code.textContent, 'text/javascript', code);

    const api = new APIDocumentation(version);

    // Add release notes if we have any.
    if (releaseNotes) {
      api.sections.push(APISection.create(api, 'Release Notes', APIDocumentation._markdownToDOM(releaseNotes)));
    }

    // All class headers are rendered as H3 tags
    const headers = doc.querySelectorAll('h3');
    for (let i = 0; i < headers.length; ++i) {
      const header = headers[i];
      const nextHeader = i + 1 < headers.length ? headers[i + 1] : null;
      const title = header.textContent;
      // Import all HTML from section until we hit next top-level header.
      const content = extractSiblingsIntoFragment(header.nextSibling, nextHeader);
      if (title.toLowerCase().startsWith('class:'))
        api.classes.push(APIClass.create(api, title, content));
      else
        api.sections.push(APISection.create(api, title, content));
    }
    api._initializeContentIds();
    for (const apiClass of api.classes)
      apiClass._initializeTableOfContents();
    return api;
  }

  static _idFromGHAnchor(githubAnchor) {
    return 'api-' + githubAnchor;
  }

  constructor(version) {
    this.version = version;
    this.sections = [];
    this.classes = [];

    this._defaultContentId = null;
    this._idToEntry = new Map();
  }

  defaultContentId() {
    return this._defaultContentId;
  }

  _initializeContentIds() {
    const generateGithubAnchor = (title) => {
      const id = title.trim().toLowerCase().replace(/\s/g, '-').replace(/[^-0-9a-zа-яё]/ig, '');
      let dedupId = id;
      let counter = 0;
      while (this._idToEntry.has(dedupId))
        dedupId = id + '-' + (++counter);
      return dedupId;
    }

    const assignId = (entry, title) => {
      const contentId = APIDocumentation._idFromGHAnchor(generateGithubAnchor(title));
      entry.contentId = contentId;
      this._idToEntry.set(contentId, entry);
    };

    for (const section of this.sections)
      assignId(section, section.name);
    for (const apiClass of this.classes) {
      assignId(apiClass, `class: '${apiClass.name}'`);
      for (const apiEvent of apiClass.events)
        assignId(apiEvent, `event: '${apiEvent.name}'`);
      for (const apiMethod of apiClass.methods)
        assignId(apiMethod, `${apiClass.loweredName}.${apiMethod.name}(${apiMethod.args})`);
      for (const ns of apiClass.namespaces)
        assignId(ns, `${apiClass.loweredName}.${ns.name}`);
    }

    this._defaultContentId = this._idToEntry.keys().next().value;
  }

  idToEntry(id) {
    return this._idToEntry.get(id) || null;
  }
}

class APIEntry {
  constructor(api, name, element, contentId) {
    this.api = api;
    this.name = name;
    this.element = element;
    // This has to be assigned later.
    this.contentId = null;
  }

  linkURL() {
    return app.linkURL(this.api.version, this.contentId);
  }
}

class APISection extends APIEntry {
  static create(api, title, descFragment) {
    const element = document.createElement('api-section');
    element.classList.add('api-entry');
    element.innerHTML = `<h1>${title}</h1>`;
    element.appendChild(descFragment);
    return new APISection(api, title, element);
  }

  constructor(api, name, element) {
    super(api, name, element);
  }
}

class APIClass extends APIEntry {
  static create(api, title, fragment) {
    const name = title.replace(/^class:/i, '').trim();
    const headers = fragment.querySelectorAll('h4');

    const element = document.createElement('api-class');
    element.classList.add('api-entry');
    element.innerHTML = `<h3><pptr-class-icon></pptr-class-icon><api-class-name>class: ${name}</api-class-name></h3>`;
    element.appendChild(extractSiblingsIntoFragment(fragment.firstChild, headers[0]));
    const apiClass = new APIClass(api, name, element);

    for (let i = 0; i < headers.length; ++i) {
      const header = headers[i];
      const nextHeader = i + 1 < headers.length ? headers[i + 1] : null;
      const title = header.textContent;
      const fragment = extractSiblingsIntoFragment(header.nextSibling, nextHeader);
      if (title.toLowerCase().startsWith('event:'))
        apiClass.events.push(APIEvent.create(apiClass, title, fragment));
      else if (title.includes('('))
        apiClass.methods.push(APIMethod.create(apiClass, title, fragment));
      else
        apiClass.namespaces.push(APINamespace.create(apiClass, title, fragment));
    }
    return apiClass;
  }

  constructor(api, name, element) {
    super(api, name, element);
    this.loweredName = name.substring(0, 1).toLowerCase() + name.substring(1);
    this.methods = [];
    this.events = [];
    this.namespaces = [];
  }

  _initializeTableOfContents() {
    const addHeader = (tagName, text) => {
      const header = document.createElement(tagName);
      header.textContent = text;
      this.element.appendChild(header);
    };

    if (this.events.length) {
      addHeader('h4', 'Events');
      const ul = document.createElement('ul');
      for (const apiEvent of this.events)
        createTOC(ul, `${this.loweredName}.on('${apiEvent.name}')`, apiEvent);
      this.element.appendChild(ul);
    }
    if (this.namespaces.length) {
      addHeader('h4', 'Namespaces');
      const ul = document.createElement('ul');
      for (const ns of this.namespaces)
        createTOC(ul, this.loweredName + '.' + ns.name, ns);
      this.element.appendChild(ul);
    }
    if (this.methods.length) {
      addHeader('h4', 'Methods');
      const ul = document.createElement('ul');
      for (const apiMethod of this.methods)
        createTOC(ul, `${this.loweredName}.${apiMethod.name}(${apiMethod.args})`, apiMethod);
      this.element.appendChild(ul);
    }

    function createTOC(ul, text, entity) {
      const li = document.createElement('li');
      li.innerHTML = `<a href=${entity.linkURL()}>${text}</a>`;
      ul.appendChild(li);
    }

  }
}

class APINamespace extends APIEntry {
  static create(apiClass, title, fragment) {
    const name = title.split('.').pop();
    const element = document.createElement('api-ns');
    element.classList.add('api-entry');
    element.innerHTML = [
      `<h4>`,
        '<pptr-ns-icon></pptr-ns-icon>',
        `<api-ns-classname>${apiClass.loweredName}</api-ns-classname>`,
        `<api-ns-name>.${name}</api-ns-name>`,
      `</h4>`
    ].join('');
    element.appendChild(fragment);
    return new APINamespace(apiClass, name, element);
  }

  constructor(apiClass, name, element) {
    super(apiClass.api, name, element);
    this.apiClass = apiClass;
  }
}

class APIMethod extends APIEntry {
  static create(apiClass, title, descFragment) {
    const name = title.match(/\.([^(]*)/)[1];
    const args = title.match(/\((.*)\)/)[1];
    const element = document.createElement('api-method');
    element.classList.add('api-entry');
    element.innerHTML = [
      `

        <pptr-method-icon></pptr-method-icon>
        <api-method-classname>${apiClass.loweredName}</api-method-classname>`,
        `<api-method-name>.${name}</api-method-name>`,
        `<api-method-args>(${args})</api-method-args>`,
      `</h4>`
    ].join('');
    element.appendChild(descFragment);
    return new APIMethod(apiClass, name, args, element);
  }

  constructor(apiClass, name, args, element) {
    super(apiClass.api, name, element);
    this.apiClass = apiClass;
    this.args = args;
  }
}

class APIEvent extends APIEntry {
  static create(apiClass, title, descFragment) {
    const name = title.match(/'(.*)'/)[1];
    const element = document.createElement('api-event');
    element.classList.add('api-entry');
    element.innerHTML = `<h4><pptr-event-icon></pptr-event-icon>${apiClass.loweredName}.on(<api-event-name>'${name}'</api-event-name>)</h4>`;
    element.appendChild(descFragment);
    return new APIEvent(apiClass, name, element);
  }

  constructor(apiClass, name, element) {
    super(apiClass.api, name, element);
    this.apiClass = apiClass;
  }
}

/**
 * @param {!Node} fromInclusive
 * @param {!Node} toExclusive
 * @return {!DocumentFragment}
 */
function extractSiblingsIntoFragment(fromInclusive, toExclusive) {
  const fragment = document.createDocumentFragment();
  let node = fromInclusive;
  while (node && node !== toExclusive) {
    const next = node.nextSibling;
    fragment.appendChild(node);
    node = next;
  }
  return fragment;
}

<|endoftext|>


<commit_before>// Copyright (c) 2013, Benjamin J. Kelly ("Author")
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

'use strict';

module.exports = ObjectTransform;

var Transform = require('stream').Transform;
if (!Transform) {
  Transform = require('readable-stream/transform');
}
var util = require('util');

util.inherits(ObjectTransform, Transform);

function ObjectTransform(opts) {
  var self = (this instanceof ObjectTransform)
           ? this
           : Object.create(ObjectTransform.prototype);

  opts = opts || {};

  if (opts.objectMode === false) {
    throw new Error('ObjectTransform requires stream objectMode; do not set ' +
                    'option {objectMode: false}');
  }
  opts.objectMode = true;

  Transform.call(self, opts);

  self._metaProp = opts.meta;

  if (self._metaProp && typeof self._metaProp !== 'string') {
    throw new Error('ObjectTransform optional "meta" property must be a ' +
                    'string specifying the msg property where metadata will ' +
                    'be stored.');
  }

  self[self._metaProp] = opts[self._metaProp];

  return self;
}

ObjectTransform.prototype._transform = function(origMsg, output, callback) {
  var msg = origMsg;
  if (Buffer.isBuffer(msg)) {
    msg = { data: msg, offset: 0 };
  }
  msg.offset = ~~msg.offset;

  var metaData = null;
  if (this._metaProp) {
    metaData = msg[this._metaProp] || this[this._metaProp];
  }

  try {
    var msgOut = null;

    if (metaData) {
      msg.data = this._grow(msg.data, msg.offset, ~~metaData.length);
      msgOut = this._expand(metaData, msg, output, callback);
    } else {
      msgOut = this._reduce(msg, output, callback);
    }

    // convenience for sync, one-to-one _expand/_reduce functions
    if (msgOut) {
      output(msgOut);
      callback();
    }

  } catch (error) {
    this.emit('ignored', error, origMsg);
    callback();
  }
};

ObjectTransform.prototype._grow = function(buf, offset, length) {
  var reqLength = offset + length;
  if (reqLength <= buf.length) {
    return buf;
  }
  if (!buf) {
    return new Buffer(reqLength);
  }
  var newBuf = new Buffer(reqLength);
  buf.copy(newBuf, 0, 0, offset);
  return newBuf;
};

ObjectTransform.prototype._expand = function(metaData, msg, output, callback) {
  throw new Error('ObjectTransform._expand() not implemented');
};

ObjectTransform.prototype._reduce = function(msg, output, callback) {
  throw new Error('ObjectTransform._reduce() not implemented');
};
<commit_msg>Add compatibility for new _transform() API in master.  The output function has been removed.<commit_after>// Copyright (c) 2013, Benjamin J. Kelly ("Author")
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

'use strict';

module.exports = ObjectTransform;

var Transform = require('stream').Transform;
if (!Transform) {
  Transform = require('readable-stream/transform');
}
var util = require('util');

util.inherits(ObjectTransform, Transform);

function ObjectTransform(opts) {
  var self = (this instanceof ObjectTransform)
           ? this
           : Object.create(ObjectTransform.prototype);

  opts = opts || {};

  if (opts.objectMode === false) {
    throw new Error('ObjectTransform requires stream objectMode; do not set ' +
                    'option {objectMode: false}');
  }
  opts.objectMode = true;

  Transform.call(self, opts);

  self._metaProp = opts.meta;

  if (self._metaProp && typeof self._metaProp !== 'string') {
    throw new Error('ObjectTransform optional "meta" property must be a ' +
                    'string specifying the msg property where metadata will ' +
                    'be stored.');
  }

  self[self._metaProp] = opts[self._metaProp];

  return self;
}

ObjectTransform.prototype._transform = function(origMsg, output, callback) {
  var self = this;

  // Compat for differences between readable-stream v0.3.0 and current master.
  // The output argument was removed.
  // TODO: remove once the API has been pushed to readable-stream.
  if (typeof callback !== 'function') {
    callback = output;
    output = function(msg) {
      self.push(msg);
    };
  }

  var msg = origMsg;
  if (Buffer.isBuffer(msg)) {
    msg = { data: msg, offset: 0 };
  }
  msg.offset = ~~msg.offset;

  var metaData = null;
  if (this._metaProp) {
    metaData = msg[self._metaProp] || self[self._metaProp];
  }

  try {
    var msgOut = null;

    if (metaData) {
      msg.data = self._grow(msg.data, msg.offset, ~~metaData.length);
      msgOut = self._expand(metaData, msg, output, callback);
    } else {
      msgOut = self._reduce(msg, output, callback);
    }

    // convenience for sync, one-to-one _expand/_reduce functions
    if (msgOut) {
      output(msgOut);
      callback();
    }

  } catch (error) {
    self.emit('ignored', error, origMsg);
    callback();
  }
};

ObjectTransform.prototype._grow = function(buf, offset, length) {
  var reqLength = offset + length;
  if (reqLength <= buf.length) {
    return buf;
  }
  if (!buf) {
    return new Buffer(reqLength);
  }
  var newBuf = new Buffer(reqLength);
  buf.copy(newBuf, 0, 0, offset);
  return newBuf;
};

ObjectTransform.prototype._expand = function(metaData, msg, output, callback) {
  throw new Error('ObjectTransform._expand() not implemented');
};

ObjectTransform.prototype._reduce = function(msg, output, callback) {
  throw new Error('ObjectTransform._reduce() not implemented');
};
<|endoftext|>


<commit_before>/*jslint white: true*/
module.exports = function (config) {
    'use strict';
    config.set({
        basePath: '../../',
        frameworks: ['jasmine', 'requirejs'],
        plugins: [
            'karma-jasmine',
            // 'karma-chrome-launcher',
            'karma-phantomjs-launcher',
            'karma-coverage',
            'karma-requirejs'
        ],
        files: [
            // {pattern: 'kbase-extension/static/components/**/*.js', included: false},
            // {pattern: 'kbase-extension/static/kbase/js/*.js', included: false},
            // {pattern: 'kbase-extension/static/kbase/js/widgets/**/*.js', included: false},
            // {pattern: 'kbase-extension/static/**/*.json', included: false},

            {pattern: 'test/unit/spec/**/*.js', included: false},
            'kbase-extension/static/narrative_paths.js',
            'test/unit/test-main.js'
        ],
        // test results reporter to use
        // possible values: 'dots', 'progress'
        // available reporters: https://npmjs.org/browse/keyword/karma-reporter
        reporters: ['progress', 'coverage'],
        // 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: false,
        // start these browsers
        // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
        browsers: ['PhantomJS'],
        // Continuous Integration mode
        // if true, Karma captures browsers, runs the tests and exits
        singleRun: true,
        proxies: {
            '/narrative/static/': 'http://localhost:8888/narrative/static/',
            '/static/': 'http://localhost:8888/narrative/static/'
        }

    });
};
<commit_msg>More test fixes... silly port.<commit_after>/*jslint white: true*/
module.exports = function (config) {
    'use strict';
    config.set({
        basePath: '../../',
        frameworks: ['jasmine', 'requirejs'],
        plugins: [
            'karma-jasmine',
            // 'karma-chrome-launcher',
            'karma-phantomjs-launcher',
            'karma-coverage',
            'karma-requirejs'
        ],
        files: [
            // {pattern: 'kbase-extension/static/components/**/*.js', included: false},
            // {pattern: 'kbase-extension/static/kbase/js/*.js', included: false},
            // {pattern: 'kbase-extension/static/kbase/js/widgets/**/*.js', included: false},
            // {pattern: 'kbase-extension/static/**/*.json', included: false},

            {pattern: 'test/unit/spec/**/*.js', included: false},
            'kbase-extension/static/narrative_paths.js',
            'test/unit/test-main.js'
        ],
        // test results reporter to use
        // possible values: 'dots', 'progress'
        // available reporters: https://npmjs.org/browse/keyword/karma-reporter
        reporters: ['progress', 'coverage'],
        // 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: false,
        // start these browsers
        // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
        browsers: ['PhantomJS'],
        // Continuous Integration mode
        // if true, Karma captures browsers, runs the tests and exits
        singleRun: true,
        proxies: {
            '/narrative/static/': 'http://localhost:9999/narrative/static/',
            '/static/': 'http://localhost:9999/narrative/static/'
        }

    });
};
<|endoftext|>


<commit_before>'use strict';
const _ = require('lodash');

module.exports = (model) => {
  model.getUpdateableAttributes = function () {
    return _.pull(Object.keys(this.attributes), 'id', 'updatedAt', 'createdAt', 'deletedAt')
      .map(attribute => {
        const allowNull = this.attributes[attribute].allowNull;
        return {attribute, allowNull: allowNull === undefined || allowNull === true};
      });
  };

  model.getReferenceAttributes = function () {
    return _.pull(Object.keys(this.attributes), 'id', 'updatedAt', 'createdAt', 'deletedAt')
      .filter(attribute => this.attributes[attribute].references);
  };

  model.getReferences = function () {
    return Object.keys(this.attributes)
      .filter(attribute => this.attributes[attribute].references)
      .map(attribute => {
        const field = this.attributes[attribute];
        return {
          model: field.Model,
          key: field.fieldName
        };
      });
  };

  model.filterReferenceAttributesFromModelInstance = function (input) {
    const referenceAttributes = this.getReferenceAttributes();
    return _.omit(input, referenceAttributes);
  };

  model.removeIllegalAttributes = function (input) {
    return _.pick(input, this.getUpdateableAttributes().map(attr => attr.attribute));
  };

  model.fillMissingUpdateableAttributes = function (association, source, input) {
    const result = this.getUpdateableAttributes().reduce((result, current) => {
      if (input[current.attribute] !== undefined) result[current.attribute] = input[current.attribute];
      else result[current.attribute] = null;
      return result;
    }, {});
    // foreign key is required and not inside the body. will only trigger if this is a relation
    if (association && (association.associationType === 'HasOne' || association.associationType === 'HasMany') &&
      !result[association.foreignKey]) {
      result[association.foreignKey] = source.id;
    }
    return result;
  };

  model.getAssociatedModelNames = function () {
    return _.keys(this.associations);
  };

  model.getAssociationByName = function (name) {
    return this.associations[name];
  };

  model.getAssociationByModel = function (associatedModel) {
    const keys = Object.keys(this.associations);
    for (let i = 0; i < keys.length; i++) {
      const k = keys[i];
      if (this.associations[k].target === associatedModel) {
        return this.associations[k];
      }
    }
    throw new Error(`${this.name} has no association to ${associatedModel.name}!`);
  };

  model.getModelAssociations = function () {
    const result = [];
    this.getAssociatedModelNames().forEach(associationName => {
      const association = this.getAssociationByName(associationName);
      const target = association.target;
      const source = association.source;
      switch (association.associationType) {
        case 'HasOne':
        case 'HasMany':
          return result.push({
            source,
            target,
            associationType: association.associationType,
            fk: association.foreignKeyField || association.foreignKey,
            as: association.as
          });
        case 'BelongsToMany':
          return result.push({
            source,
            target,
            associationType: association.associationType,
            through: association.throughModel,
            sourceFk: association.foreignKeyField || association.foreignKey,
            targetFk: association.otherKeyField || association.otherKey,
            as: association.as
          });
        case 'BelongsTo':
          return result.push({
            source,
            target,
            associationType: association.associationType,
            fk: association.foreignKeyField || association.foreignKey,
            as: association.as
          });
      }
    });
    return result;
  };
};
<commit_msg>removed lodash call<commit_after>'use strict';
const _ = require('lodash');

module.exports = (model) => {
  model.getUpdateableAttributes = function () {
    return _.pull(Object.keys(this.attributes), 'id', 'updatedAt', 'createdAt', 'deletedAt')
      .map(attribute => {
        const allowNull = this.attributes[attribute].allowNull;
        return {attribute, allowNull: allowNull === undefined || allowNull === true};
      });
  };

  model.getReferenceAttributes = function () {
    return _.pull(Object.keys(this.attributes), 'id', 'updatedAt', 'createdAt', 'deletedAt')
      .filter(attribute => this.attributes[attribute].references);
  };

  model.getReferences = function () {
    return Object.keys(this.attributes)
      .filter(attribute => this.attributes[attribute].references)
      .map(attribute => {
        const field = this.attributes[attribute];
        return {
          model: field.Model,
          key: field.fieldName
        };
      });
  };

  model.filterReferenceAttributesFromModelInstance = function (input) {
    const referenceAttributes = this.getReferenceAttributes();
    return _.omit(input, referenceAttributes);
  };

  model.removeIllegalAttributes = function (input) {
    return _.pick(input, this.getUpdateableAttributes().map(attr => attr.attribute));
  };

  model.fillMissingUpdateableAttributes = function (association, source, input) {
    const result = this.getUpdateableAttributes().reduce((result, current) => {
      if (input[current.attribute] !== undefined) result[current.attribute] = input[current.attribute];
      else result[current.attribute] = null;
      return result;
    }, {});
    // foreign key is required and not inside the body. will only trigger if this is a relation
    if (association && (association.associationType === 'HasOne' || association.associationType === 'HasMany') &&
      !result[association.foreignKey]) {
      result[association.foreignKey] = source.id;
    }
    return result;
  };

  model.getAssociatedModelNames = function () {
    return Object.keys(this.associations);
  };

  model.getAssociationByName = function (name) {
    return this.associations[name];
  };

  model.getAssociationByModel = function (associatedModel) {
    const keys = Object.keys(this.associations);
    for (let i = 0; i < keys.length; i++) {
      const k = keys[i];
      if (this.associations[k].target === associatedModel) {
        return this.associations[k];
      }
    }
    throw new Error(`${this.name} has no association to ${associatedModel.name}!`);
  };

  model.getModelAssociations = function () {
    const result = [];
    this.getAssociatedModelNames().forEach(associationName => {
      const association = this.getAssociationByName(associationName);
      const target = association.target;
      const source = association.source;
      switch (association.associationType) {
        case 'HasOne':
        case 'HasMany':
          return result.push({
            source,
            target,
            associationType: association.associationType,
            fk: association.foreignKeyField || association.foreignKey,
            as: association.as
          });
        case 'BelongsToMany':
          return result.push({
            source,
            target,
            associationType: association.associationType,
            through: association.throughModel,
            sourceFk: association.foreignKeyField || association.foreignKey,
            targetFk: association.otherKeyField || association.otherKey,
            as: association.as
          });
        case 'BelongsTo':
          return result.push({
            source,
            target,
            associationType: association.associationType,
            fk: association.foreignKeyField || association.foreignKey,
            as: association.as
          });
      }
    });
    return result;
  };
};
<|endoftext|>


<commit_before>'use strict';

var expect = require('chai').expect,
  f = require('util').format,
  fs = require('fs'),
  ObjectId = require('bson').ObjectId,
  ReplSetState = require('../../../lib/topologies/replset_state');

describe('A replica set state', function() {
  it('should correctly execute state machine tests', {
    metadata: { requires: { topology: 'single' } },

    test: function(done) {
      var path = f('%s/../topology_test_descriptions/rs', __dirname);
      var entries = fs.readdirSync(path).filter(function(x) {
        return x.indexOf('.json') !== -1;
      });

      // Execute each of the entries
      entries.forEach(function(x) {
        executeEntry(f('%s/%s', path, x));
      });

      done();
    }
  });
});

function executeEntry(path) {
  // Read and parse the json file
  var file = require(path);
  // Unpack entry
  var description = file.description;
  var uri = file.uri;
  var phases = file.phases;

  console.log(f('+ Starting: %s [%s]', description, path.split(/\//).pop()));

  // Get replicaset name if any
  var match = uri.match(/replicaSet=[a-z|A-Z|0-9]*/);
  var replicaSet = match ? match.toString().split(/=/)[1] : null;

  // Replicaset
  // Create a replset state
  var state = new ReplSetState({ setName: replicaSet });

  // Get all the server instances
  var parts = uri
    .split('mongodb://')[1]
    .split('/')[0]
    .split(',');
  // For each of the servers
  parts.forEach(function(x) {
    var params = x.split(':');
    state.update({
      name: f('%s:%s', params[0], params[1] ? parseInt(params[1], 10) : 27017),
      lastIsMaster: function() {
        return null;
      },
      equals: function(s) {
        if (typeof s === 'string') return s === this.name;
        return s.name === this.name;
      },
      destroy: function() {}
    });
  });

  // Run each phase
  phases.forEach(function(x) {
    executePhase(state, x);
  });
}

function executePhase(state, phase) {
  var responses = phase.responses;
  var outcome = phase.outcome;

  // Apply all the responses
  responses.forEach(function(x) {
    if (Object.keys(x[1]).length === 0) {
      state.remove({
        name: x[0],
        lastIsMaster: function() {
          return null;
        },
        equals: function(s) {
          if (typeof s === 'string') return s === this.name;
          return s.name === this.name;
        },
        destroy: function() {}
      });
    } else {
      var ismaster = x[1];
      if (ismaster.electionId) ismaster.electionId = new ObjectId(ismaster.electionId.$oid);

      state.update({
        name: x[0],
        lastIsMaster: function() {
          return ismaster;
        },
        equals: function(s) {
          if (typeof s === 'string') return s === this.name;
          return s.name === this.name;
        },
        destroy: function() {}
      });
    }
  });

  // Validate the state of the final outcome
  for (var name in outcome.servers) {
    try {
      if (outcome.servers[name].electionId) {
        outcome.servers[name].electionId = new ObjectId(outcome.servers[name].electionId.$oid);
      }

      expect(state.set[name]).to.exist;
      for (var n in outcome.servers[name]) {
        if (outcome.servers[name][n]) {
          expect(outcome.servers[name][n]).to.eql(state.set[name][n]);
        }
      }
    } catch (e) {
      console.log('========================== 0');
      console.dir(outcome.servers);
      console.log('========================== 1');
      console.dir(state.set);
      process.exit(0);
    }
  }

  // // Check the topology type
  expect(outcome.topologyType).to.equal(state.topologyType);
  expect(outcome.setName).to.equal(state.setName);
}
<commit_msg>test(replset-state): convert auto-tests to run as mocha tests<commit_after>'use strict';

const expect = require('chai').expect,
  p = require('path'),
  f = require('util').format,
  fs = require('fs'),
  ObjectId = require('bson').ObjectId,
  ReplSetState = require('../../../lib/topologies/replset_state');

describe('ReplicaSet state', function() {
  const path = f('%s/../topology_test_descriptions/rs', __dirname);

  fs
    .readdirSync(path)
    .filter(x => x.indexOf('.json') !== -1)
    .forEach(x => {
      var testData = require(f('%s/%s', path, x));

      it(testData.description, function(done) {
        executeEntry(testData, done);
      });
    });
});

function executeEntry(testData, callback) {
  var uri = testData.uri;
  var phases = testData.phases;

  // Get replicaset name if any
  var match = uri.match(/replicaSet=[a-z|A-Z|0-9]*/);
  var replicaSet = match ? match.toString().split(/=/)[1] : null;

  // Replicaset
  // Create a replset state
  var state = new ReplSetState({ setName: replicaSet });

  // Get all the server instances
  var parts = uri
    .split('mongodb://')[1]
    .split('/')[0]
    .split(',');

  // For each of the servers
  parts.forEach(function(x) {
    var params = x.split(':');
    state.update({
      name: f('%s:%s', params[0], params[1] ? parseInt(params[1], 10) : 27017),
      lastIsMaster: function() {
        return null;
      },
      equals: function(s) {
        if (typeof s === 'string') return s === this.name;
        return s.name === this.name;
      },
      destroy: function() {}
    });
  });

  // Run each phase
  executePhases(phases, state, callback);
}

function executePhases(phases, state, callback) {
  if (phases.length === 0) {
    return callback(null, null);
  }

  executePhase(phases.shift(), state, err => {
    if (err) return callback(err, null);
    return executePhases(phases, state, callback);
  });
}

function executePhase(phase, state, callback) {
  var responses = phase.responses;
  var outcome = phase.outcome;

  // Apply all the responses
  responses.forEach(function(x) {
    if (Object.keys(x[1]).length === 0) {
      state.remove({
        name: x[0],
        lastIsMaster: function() {
          return null;
        },
        equals: function(s) {
          if (typeof s === 'string') return s === this.name;
          return s.name === this.name;
        },
        destroy: function() {}
      });
    } else {
      var ismaster = x[1];
      if (ismaster.electionId) ismaster.electionId = new ObjectId(ismaster.electionId.$oid);

      state.update({
        name: x[0],
        lastIsMaster: function() {
          return ismaster;
        },
        equals: function(s) {
          if (typeof s === 'string') return s === this.name;
          return s.name === this.name;
        },
        destroy: function() {}
      });
    }
  });

  // Validate the state of the final outcome
  for (var name in outcome.servers) {
    try {
      if (outcome.servers[name].electionId) {
        outcome.servers[name].electionId = new ObjectId(outcome.servers[name].electionId.$oid);
      }

      expect(state.set[name]).to.exist;
      for (var n in outcome.servers[name]) {
        if (outcome.servers[name][n]) {
          expect(outcome.servers[name][n]).to.eql(state.set[name][n]);
        }
      }
    } catch (e) {
      return callback(e);
    }
  }

  // // Check the topology type
  expect(outcome.topologyType).to.equal(state.topologyType);
  expect(outcome.setName).to.equal(state.setName);
  callback(null, null);
}
<|endoftext|>


<commit_before>/*
 * This file is part of Invenio.
 * Copyright (C) 2014 CERN.
 *
 * Invenio is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * Invenio 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Invenio; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 */

'use strict';

define(['js/groups/remote.autocomplete.field'], function(autocomplete) {
  "use strict"

  describe("A suite", function() {

    beforeEach(function () {
      $('#test-form').remove()
      jasmine.getFixtures().fixturesPath = '/jasmine/spec/invenio.modules.groups/fixtures/'
      $('body').append(readFixtures('test.html'))
    });

    afterEach(function(){
      $('#test-form').remove()
    })

    it("Autocomplete text is as expected", function() {
      autocomplete()

      var obj = $('#user_id')
      var iobj = $('#user_id_interface')

      expect(iobj.attr('type')).toBe('text');
      expect(iobj.attr('data-autocomplete-data-value')).toBe('nickname');
      expect(iobj.attr('data-autocomplete-data-key')).toBe('id');
      expect(iobj.attr('data-autocomplete-highlight')).toBe('true');
      expect(iobj.attr('data-autocomplete-minlength')).toBe('2');
      expect(iobj.attr('data-autocomplete-displaykey')).toBe('nickname');
      expect(iobj.attr('data-autocomplete-remote')).toBe('spec/invenio.modules.groups/fixtures/users.json?name=%QUERY');

      expect(obj.attr('type')).toBe('hidden');
      expect(obj.attr('name')).toBe('user_id');
    });
  });

});
<commit_msg>groups: jasmine tests adaptation to requirejs<commit_after>/*
 * This file is part of Invenio.
 * Copyright (C) 2014 CERN.
 *
 * Invenio is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * Invenio 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Invenio; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 */

'use strict';

define([
  'js/groups/remote.autocomplete.field',
  'jasmine-jquery',
], function(autocomplete, jasmineJQuery) {
  "use strict"

  describe("A suite", function() {

    beforeEach(function () {
      $('#test-form').remove()
      jasmine.getFixtures().fixturesPath = '/jasmine/spec/invenio.modules.groups/fixtures/'
      $('body').append(readFixtures('test.html'))
    });

    afterEach(function(){
      $('#test-form').remove()
    })

    it("Autocomplete text is as expected", function() {
      autocomplete()

      var obj = $('#user_id')
      var iobj = $('#user_id_interface')

      expect(iobj.attr('type')).toBe('text');
      expect(iobj.attr('data-autocomplete-data-value')).toBe('nickname');
      expect(iobj.attr('data-autocomplete-data-key')).toBe('id');
      expect(iobj.attr('data-autocomplete-highlight')).toBe('true');
      expect(iobj.attr('data-autocomplete-minlength')).toBe('2');
      expect(iobj.attr('data-autocomplete-displaykey')).toBe('nickname');
      expect(iobj.attr('data-autocomplete-remote')).toBe('spec/invenio.modules.groups/fixtures/users.json?name=%QUERY');

      expect(obj.attr('type')).toBe('hidden');
      expect(obj.attr('name')).toBe('user_id');
    });
  });
});
<|endoftext|>