index.js
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)