 	/**
    Run executable and return before it is finished.
 
-   - parameter executable: path to an executable file.
-   - parameter args: arguments to the executable.
-   - returns: an AsyncShellTask with standard output, standard error and a 'finish' function.
+   - parameter executable: Path to an executable file. If not then exit.
+   - parameter args: Arguments to the executable.
+   - returns: An AsyncShellTask with standard output, standard error and a 'finish' function.
 	*/
 	public func runAsync (executable: String, _ args: Any ...) -> AsyncShellTask {
 		let stringargs = args.flatten().map { String($0) }

	exit(errorcode)
}

@noreturn public func exit (error: ErrorType) {
	if let shellerror = error as? ShellError {
		exit(errormessage: shellerror, errorcode: shellerror.errorcode)

		task.standardError = self.stderror

		return task
	}
}


// MARK: ShellError

/** Error type for shell commands. */
public enum ShellError: ErrorType, Equatable {

	/** Exit code was not zero. */
	case ReturnedErrorCode (errorcode: Int32)

	/** Command could not be executed. */
	case InAccessibleExecutable (path: String)

	/** Exit code for this error. */
	var errorcode: Int32 {
		switch self {
		case .ReturnedErrorCode(let code):
			return code
		case .InAccessibleExecutable:
			// according to http://tldp.org/LDP/abs/html/exitcodes.html
			return 127
		}
	}
}

extension ShellError: CustomStringConvertible {
	public var description: String {
		switch self {
		case .InAccessibleExecutable(let path):
			return "Could not execute file at path '\(path)'."
		case .ReturnedErrorCode(let code):
			return "Command returned with error code \(code)."
		}
	}
}

public func == (e1: ShellError, e2: ShellError) -> Bool {
	switch (e1, e2) {
	case (.ReturnedErrorCode(let c1), .ReturnedErrorCode(let c2)):
		return c1 == c2
	case (.InAccessibleExecutable(let c1), .InAccessibleExecutable(let c2)):
		return c1 == c2
	default:
		return false
	}
}

extension NSTask {

	/**
   Launch task.

   - throws: ShellError.InAccessibleExecutable if command could not be executed.
	*/
	public func launchThrowably() throws {
		do {
			try launchWithNSError()
		} catch {
			throw ShellError.InAccessibleExecutable(path: self.launchPath!)
		}
	}

	/**
   Wait until task is finished.

   - throws: ShellError.ReturnedErrorCode if exit code is not zero.
	*/
	public func finish() throws {
		self.waitUntilExit()
		guard self.terminationStatus == 0 else {
			throw ShellError.ReturnedErrorCode(errorcode: self.terminationStatus)
		}
	}
}

