function run(context, fn, finish, args) {
	// Argument mangling {{{
	if (typeof context == 'function') { // called as run(fn, finish, args);
		args = finish;
		finish = fn;
		fn = context;
		context = this;
	}
	// }}}

	if (isPromise(fn)) { // Given a promise that has already resolved?
		fn
			.then(function(value) {
				finish.apply(context, [null, value]);
			})
			.catch(function(err) {
				finish.call(context, err || 'An error occured');
			});
	} else if (hasCallback(fn)) { // Callback w/ (err, result) pattern
		var result = fn.apply(context, args ? [finish].concat(args) : [finish]);
		if (isPromise(result)) {
			result
				.then(function(value) { // Remap result from (val) => (err, val)
					finish.apply(context, [null, value]);
				})
				.catch(function(err) {
					finish.call(context, err || 'An error occured');
				});
		}
	} else { // Maybe either a promise or sync function?
		var result;
		try {
			result = fn.apply(context, args || []); // Run the function and see what it gives us
		} catch (e) {
			finish.call(context, e);
		}
		if (isPromise(result)) { // Got back a promise - attach to the .then() function
			result
				.then(function(value) { // Remap result from (val) => (err, val)
					finish.apply(context, [null, value]);
				})
				.catch(function(err) {
					finish.call(context, err || 'An error occured');
				});
		} else { // Didn't provide back a promise - assume it was a sync function
			finish.apply(context, [null, result]);
		}
	}
}
function run(context, fn, finish, args) {
	// Argument mangling {{{
	if (typeof context == 'function') { // called as run(fn, finish, args);
		args = finish;
		finish = fn;
		fn = context;
		context = this;
	}
	// }}}

	if (isPromise(fn)) { // Given a promise that has already resolved?
		fn
			.then(function(value) {
				finish.apply(context, [null, value]);
			})
			.catch(function(err) {
				finish.call(context, err || 'An error occured');
			});
	} else if (hasCallback(fn)) { // Callback w/ (err, result) pattern
		var result = fn.apply(context, args ? [finish].concat(args) : [finish]);
		if (isPromise(result)) {
			result
				.then(function(value) { // Remap result from (val) => (err, val)
					finish.apply(context, [null, value]);
				})
				.catch(function(err) {
					finish.call(context, err || 'An error occured');
				});
		}
	} else { // Maybe either a promise or sync function?
		var result;
		try {
			result = fn.apply(context, args || []); // Run the function and see what it gives us
		} catch (e) {
			finish.call(context, e);
		}
		if (isPromise(result)) { // Got back a promise - attach to the .then() function
			result
				.then(function(value) { // Remap result from (val) => (err, val)
					finish.apply(context, [null, value]);
				})
				.catch(function(err) {
					finish.call(context, err || 'An error occured');
				});
		} else { // Didn't provide back a promise - assume it was a sync function
			finish.apply(context, [null, result]);
		}
	}
}
function run ( context , fn , finish , args ) { // Argument mangling {{{ if ( typeof context == 'function' ) { // called as run(fn, finish, args); args = finish ; finish = fn ; fn = context ; context = this ; } // }}} if ( isPromise ( fn ) ) { // Given a promise that has already resolved? fn . then ( function ( value ) { finish . apply ( context , [ null , value ] ) ; } ) . catch ( function ( err ) { finish . call ( context , err || 'An error occured' ) ; } ) ; } else if ( hasCallback ( fn ) ) { // Callback w/ (err, result) pattern var result = fn . apply ( context , args ? [ finish ] . concat ( args ) : [ finish ] ) ; if ( isPromise ( result ) ) { result . then ( function ( value ) { // Remap result from (val) => (err, val) finish . apply ( context , [ null , value ] ) ; } ) . catch ( function ( err ) { finish . call ( context , err || 'An error occured' ) ; } ) ; } } else { // Maybe either a promise or sync function? var result ; try { result = fn . apply ( context , args || [ ] ) ; // Run the function and see what it gives us } catch ( e ) { finish . call ( context , e ) ; } if ( isPromise ( result ) ) { // Got back a promise - attach to the .then() function result . then ( function ( value ) { // Remap result from (val) => (err, val) finish . apply ( context , [ null , value ] ) ; } ) . catch ( function ( err ) { finish . call ( context , err || 'An error occured' ) ; } ) ; } else { // Didn't provide back a promise - assume it was a sync function finish . apply ( context , [ null , result ] ) ; } } }
Run a single function, promise return, promise factory or any other combination - then a callback when finished
Take a function reference and treat it as a callback style function
If the function returns a promise this behaviour is transformed into a callback style function

This function accepts all types of input functions:
- callback functions (e.g. `next => ...`)
- async functions (e.g. `async ()=> ...`)
- promise functions (e.g. `new Promise(resolve => ...)`)
- promise factories (e.g. `()=> new Promise(resolve => ...)`)

@param {Object} context The context object to pass to the function
@param {function|Promise} fn The function to run or the promise to resolve
@param {function} finish The function to call when finished
@param {array} [args] Additional arguments to pass when calling the function

@example Run a regular callback function - if func is callback its just passed through, if its a promise its mapped normally
run(func, thenFunc)
Run a single function promise return promise factory or any other combination - then a callback when finished Take a function reference and treat it as a callback style function If the function returns a promise this behaviour is transformed into a callback style function