lib/Plugin.js
function (opts, tree) {
	var fileName;
	this.tree = tree;
	this.resolved = false;
	this.dependants = [];
	// filePath
	this.filePath = opts.filePath || false;
	if (opts.filePath && typeof opts.filePath !== 'string') {
		throw new Error( 'Bad argument: filePath' );
	}
	// name without extension
	if (this.filePath) {
		fileName = path.basename( this.filePath, path.extname( this.filePath ));
	// raw
		this.raw = require( this.filePath );
	} else {
		this.raw = opts.raw;
	}
	// key
	this.key = opts.key || fileName;
	if (typeof this.key !== 'string') {
		throw new Error( 'Bad argument: key' );
	}
	if (startsWithNumber( this.key )) {
		throw new Error( 'Module name can\'t start with number: ' + this.key );
	}
	// localname
	this.localname = opts.localname || opts.key;
	// check if localname is a string and don't start with number'
	if (opts.localname && (typeof opts.localname !== 'string' || startsWithNumber( opts.localname ))) {
		throw new Error( 'Bad argument: localname' );
	}
	// processing
	if (opts.processing) {
		this.processing = opts.processing;
	}

	this.isPlugin = isPlugin( this.raw );
	if (this.isPlugin) {
		this.dependencies = getParamNames( this.raw.wiretree );
		this.isAsync = this.dependencies.indexOf( 'wtDone' ) >= 0 ? true : false;
	} else {
		this.res = getProcessed( this.processing, this.raw );
		this.resolved = true;
		this.dependencies = [];
		this.isAsync = false;
	}
	// check if group is a string and don't start with number'
	if (opts.group && (typeof opts.group !== 'string' || startsWithNumber( opts.group ))) {
		throw new Error( 'Bad argument: group' );
	}

	// set group
	if (opts.group) {
		if (opts.hidden) {
			this.hidden = true;
			this.key = this.key + uniid();
		}
		this.group = opts.group;
		// create group if not exist
		tree.groups[this.group] = tree.groups[this.group] || new Group( this.group, this.tree );
		// add plugin to group
		tree.groups[this.group].plugins[this.localname] = this;
	}

	tree.plugins[this.key] = this;
}
function (opts, tree) {
	var fileName;
	this.tree = tree;
	this.resolved = false;
	this.dependants = [];
	// filePath
	this.filePath = opts.filePath || false;
	if (opts.filePath && typeof opts.filePath !== 'string') {
		throw new Error( 'Bad argument: filePath' );
	}
	// name without extension
	if (this.filePath) {
		fileName = path.basename( this.filePath, path.extname( this.filePath ));
	// raw
		this.raw = require( this.filePath );
	} else {
		this.raw = opts.raw;
	}
	// key
	this.key = opts.key || fileName;
	if (typeof this.key !== 'string') {
		throw new Error( 'Bad argument: key' );
	}
	if (startsWithNumber( this.key )) {
		throw new Error( 'Module name can\'t start with number: ' + this.key );
	}
	// localname
	this.localname = opts.localname || opts.key;
	// check if localname is a string and don't start with number'
	if (opts.localname && (typeof opts.localname !== 'string' || startsWithNumber( opts.localname ))) {
		throw new Error( 'Bad argument: localname' );
	}
	// processing
	if (opts.processing) {
		this.processing = opts.processing;
	}

	this.isPlugin = isPlugin( this.raw );
	if (this.isPlugin) {
		this.dependencies = getParamNames( this.raw.wiretree );
		this.isAsync = this.dependencies.indexOf( 'wtDone' ) >= 0 ? true : false;
	} else {
		this.res = getProcessed( this.processing, this.raw );
		this.resolved = true;
		this.dependencies = [];
		this.isAsync = false;
	}
	// check if group is a string and don't start with number'
	if (opts.group && (typeof opts.group !== 'string' || startsWithNumber( opts.group ))) {
		throw new Error( 'Bad argument: group' );
	}

	// set group
	if (opts.group) {
		if (opts.hidden) {
			this.hidden = true;
			this.key = this.key + uniid();
		}
		this.group = opts.group;
		// create group if not exist
		tree.groups[this.group] = tree.groups[this.group] || new Group( this.group, this.tree );
		// add plugin to group
		tree.groups[this.group].plugins[this.localname] = this;
	}

	tree.plugins[this.key] = this;
}
/*!
Plugin constructor
@param {Object} opts plugin data
@param {Object} tree parent tree