<commit_before>#!/usr/bin/env swift

#if os(OSX)
    import Darwin
#else
    import Glibc
#endif

import Foundation

// MARK: Utilities

@noreturn func fail(_ message: String) {
    print()
    print("Error: \(message)")
    print("Note: Make sure you are using Swift 3.0 Preview 1")
    exit(1)
}

enum Error: ErrorProtocol { // Errors pertaining to running commands
    case system(Int32)
    case cancelled
    case terminalSize
}

let whiteSpace = [Character(" "), Character("\n"), Character("\t"), Character("\r")]

extension String {
    func trim(trimCharacters: [Character] = whiteSpace) -> String {
        // while characters
        var mutable = self
        while let next = mutable.characters.first where trimCharacters.contains(next) {
            mutable.remove(at: mutable.startIndex)
        }
        while let next = mutable.characters.last where trimCharacters.contains(next) {
            mutable.remove(at: mutable.index(before: mutable.endIndex))
        }
        return mutable
    }
}

func runWithOutput(_ command: String) throws -> String { // Command needs to use the absolute path for the executable
    // Run the command
    let fp = popen(command, "r")
    
    defer {
        pclose(fp)
    }
    
    if let fp = fp {
        // Get the output of the command
        let pathSize: Int32 = 1035
        let path : UnsafeMutablePointer<Int8> = UnsafeMutablePointer(allocatingCapacity: Int(pathSize))
        var output = ""
        while fgets(path, pathSize - 1, fp) != nil {
            output += String(cString: path)
        }
        
        return output
    } else {
        throw Error.system(1)
    }
}

func run(_ command: String) throws {
    let result = system(command)

    if result == 2 {
        throw Error.cancelled
    } else if result != 0 {
        throw Error.system(result)
    }
}

func passes(_ command: String) -> Bool {
    return system(command) == 0
}

func getInput() -> String {
    return readLine(strippingNewline: true) ?? ""
}

func commandExists(_ command: String) -> Bool {
    return system("hash \(command) 2>/dev/null") == 0
}

func fileExists(_ fileName: String) -> Bool {
    return system("ls \(fileName) > /dev/null 2>&1") == 0
}

func gitHistoryIsClean() -> Bool {
    return system("test -z \"$(git status --porcelain)\" || exit 1") == 0
}

func readPackageSwiftFile() -> String {
    let file = "./Package.swift"
    do {
        return try String(contentsOfFile: file)
    } catch {
        print()
        print("Unable to find Package.swift")
        print("Make sure you've run `vapor new` or setup your Swift project manually")
        fail("")
    }
}

func extractPackageName(from packageFile: String) -> String {
    let packageName = packageFile
        .components(separatedBy: "\n")
        .lazy
        .map { $0.trim() }
        .filter { $0.hasPrefix("name") }
        .first?
        .components(separatedBy: "\"")
        .lazy
        .filter { !$0.hasPrefix("name") }
        .first

    guard let name = packageName else {
        fail("Unable to extract package name")
    }

    return name
}

func getPackageName() -> String {
    let packageFile = readPackageSwiftFile()
    let packageName = extractPackageName(from: packageFile)
    return packageName
}

func terminalSize() throws -> (width: Int, height: Int) {
    // Get the columns and lines from tput
    let tput = "/usr/bin/tput"
    let cols = try runWithOutput("\(tput) cols").trim(trimCharacters: ["\n"])
    let lines = try runWithOutput("\(tput) lines").trim(trimCharacters: ["\n"])
    
    if let cols = Int(cols), lines = Int(lines) {
        return (cols, lines)
    } else {
        throw Error.terminalSize
    }
}

enum ANSIColor: String {
    case black = "\u{001B}[0;30m"
    case red = "\u{001B}[0;31m"
    case green = "\u{001B}[0;32m"
    case yellow = "\u{001B}[0;33m"
    case blue = "\u{001B}[0;34m"
    case magenta = "\u{001B}[0;35m"
    case cyan = "\u{001B}[0;36m"
    case white = "\u{001B}[0;37m"
    case reset = "\u{001B}[0;0m"
}

func printFancy(_ strings: [String]) {
    printFancy(strings.joined(separator: "\n"))
}

func printFancy(_ string: String) {
    let centered: String
    do {
        let size = try terminalSize()
        centered = string.centerTextBlock(width: size.width)
    } catch {
        centered = string        
    }

    let fancy = centered.colored(with: [
        "*": .magenta, 
        "~": .blue, 
        "+": .cyan, // Droplet
        "_": .magenta, 
        "/": .magenta, 
        "\\": .magenta, 
        "|": .magenta, 
        "-": .magenta, 
        ")": .magenta // Title
    ])

    print(fancy)
}

extension String {
    func centerTextBlock(width: Int, paddingCharacter: Character = " ") -> String {
        // Split the string into lines
        var lines = characters.split(separator: Character("\n")).map(String.init)
        
        // Make sure there's more than one line
        guard lines.count > 0 else {
            return ""
        }
        
        // Find the longest line
        var longestLine = 0
        for line in lines {
            if line.characters.count > longestLine {
                longestLine = line.characters.count
            }
        }
        
        // Calculate the padding and make sure it's greater than or equal to 0
        let padding = max(0, (width - longestLine) / 2)
        
        // Apply the padding to each line
        for i in 0..<lines.count {
            for _ in 0..<padding {
                lines[i].insert(paddingCharacter, at: startIndex)
            }
        }
        
        return lines.joined(separator: "\n")
    }
    
    #if os(Linux)
        func hasPrefix(_ str: String) -> Bool {
            let strGen = str.characters.makeIterator()
            let selfGen = self.characters.makeIterator()
            let seq = zip(strGen, selfGen)
            for (lhs, rhs) in seq where lhs != rhs {
                    return false
            }
            return true
        }

        func hasSuffix(_ str: String) -> Bool {
            let strGen = str.characters.reversed().makeIterator()
            let selfGen = self.characters.reversed().makeIterator()
            let seq = zip(strGen, selfGen)
            for (lhs, rhs) in seq where lhs != rhs {
                    return false
            }
            return true
        }
    #endif

    func colored(with colors: [Character: ANSIColor], default defaultColor: ANSIColor = .reset) -> String {
        // Check the string is long enough
        guard characters.count > 0 else {
            return ""
        }
        
        // Create a new string
        var newString = ""
        
        // Add the string to the new string and color it
        var currentColor: ANSIColor = defaultColor
        for character in characters {
            // Check if there is a new color for this character than the one before
            if (colors[character] ?? defaultColor) != currentColor {
                currentColor = colors[character] ?? defaultColor // Update the current color
                newString += currentColor.rawValue // Add the color the new string
            }
            
            newString += String(character) // Add the character to the string
        }
        
        // Reset the colors
        newString += ANSIColor.reset.rawValue
        
        return newString
    }

    func colored(with color: ANSIColor) -> String {
        return color.rawValue + self + ANSIColor.reset.rawValue
    }
}

extension Sequence where Iterator.Element == String {
    func valueFor(argument name: String) -> String? {
        for argument in self where argument.hasPrefix("--\(name)=") {
            return argument.characters.split(separator: "=").last.flatMap(String.init)
        }
        return nil
    }
}

extension Array where Element: Equatable {
    mutating func remove(_ element: Element) {
        self = self.filter { $0 != element }
    }

    mutating func remove(matching: (Element) -> Bool) {
        self = self.filter { !matching($0) }
    }
}


let asciiArt: [String] = [
    "               **",
    "             **~~**",
    "           **~~~~~~**",
    "         **~~~~~~~~~~**",
    "       **~~~~~~~~~~~~~~**",
    "     **~~~~~~~~~~~~~~~~~~**",
    "   **~~~~~~~~~~~~~~~~~~~~~~**",
    "  **~~~~~~~~~~~~~~~~~~~~~~~~**",
    " **~~~~~~~~~~~~~~~~~~~~~~~~~~**",
    "**~~~~~~~~~~~~~~~~~~~~~~~~~~~~**",
    "**~~~~~~~~~~~~~~~~~~~~~~~~~~~~**",
    "**~~~~~~~~~~~~~~~~~~~~~++++~~~**",
    " **~~~~~~~~~~~~~~~~~~~++++~~~**",
    "  ***~~~~~~~~~~~~~~~++++~~~***",
    "    ****~~~~~~~~~~++++~~****",
    "       *****~~~~~~~~~*****",
    "          *************",
    " ",
    " _       __    ___   ___   ___",
    "\\ \\  /  / /\\  | |_) / / \\ | |_)",
    " \\_\\/  /_/--\\ |_|   \\_\\_/ |_| \\",
    "   a web framework for Swift",
    " "
]


// MARK: Command

protocol Command {
    static var id: String { get }
    static var help: [String] { get }

    static var dependencies: [String] { get }
    static var subCommands: [Command.Type] { get }
    static func execute(with args: [String], in directory: String)
}

extension Command {
    static var dependencies: [String] { return [] }
    static var help: [String] { return [] }
}

// sub command related methods
extension Command {
    static var subCommands: [Command.Type] { return [] }

    static func subCommand(forId id: String) -> Command.Type? {
        return subCommands.lazy.filter { $0.id == id }.first
    }

    static func executeSubCommand(with args: [String], in directory: String) {
        var iterator = args.makeIterator()
        guard let cmdId = iterator.next() else {
            fail("\(id) requires a sub command:\n" + description)
        }
        guard let subcommand = subCommand(forId: cmdId) else {
            fail("Unknown \(id) subcommand '\(cmdId)':\n" + description)
        }
        let passthroughArgs = Array(iterator)
        subcommand.execute(with: passthroughArgs, in: directory)
    }
}

extension Command {
    static var description: String {
        // Sub Commands
        let subCommandRows: [String] = subCommands.map { subCommand in
            var output = "      \(subCommand.id.colored(with: .blue)):" 

            if subCommand.help.count > 0 {
                output += "\n"
                output += subCommand.help.map { row in 
                    return "          \(row)"
                }.joined(separator: "\n")
                output += "\n"
            }

            return output
        }
        let subCommandOutput = "\n" + subCommandRows.joined(separator: "\n")

        // Command
        var output = "  \(id.colored(with: .magenta)):"

        if help.count > 0 {
            output += "\n"

            output += help.map { row in
                return "      \(row)"
            }.joined(separator: "\n")

            output += "\n"
        }

        output += subCommandOutput

        return output
    }
}

extension Command {
    static func assertDependenciesSatisfied() {
        for dependency in dependencies where !commandExists(dependency) {
            fail("\(id) requires \(dependency)")
        }
    }
}

// MARK: Tree

var commands: [Command.Type] = []

func getCommand(id: String) -> Command.Type? {
    return commands
        .lazy
        .filter { $0.id == id }
        .first
}

// MARK: Help

struct Help: Command {
    static let id = "help"
    static func execute(with args: [String], in directory: String) {
        print("Usage: \(directory) [\(commands.map({ $0.id }).joined(separator: "|"))]")

        var help = "\nAvailable Commands:\n\n"
        help += commands
            .map { cmd in cmd.description }//"  \(cmd.id):\n\(cmd.description)\n"}
            .joined(separator: "\n")
        help += "\n"
        print(help)

        print("Community:")
        print("    Join our Slack if you have questions,")
        print("    need help, or want to contribute.")
        print("    http://slack.qutheory.io")
        print()
    }
}

commands.append(Help)

// MARK: Clean

struct Clean: Command {
    static let id = "clean"
    static func execute(with args: [String], in directory: String) {
        guard args.isEmpty else {
            fail("\(id) doesn't take any additional parameters")
        }

        do {
            try run("rm -rf Packages .build")
            print("Cleaned.")
        } catch {
            fail("Could not clean.")
        }
    }
}

commands.append(Clean)

// MARK: Build

struct Build: Command {
    static let id = "build"
    static func execute(with args: [String], in directory: String) {
        do {
            try run("swift package fetch")
        } catch Error.cancelled {
            fail("Fetch cancelled")
        } catch {
            fail("Could not fetch dependencies.")
        }

        do {
            try run("rm -rf Packages/Vapor-*/Sources/Development")
            try run("rm -rf Packages/Vapor-*/Sources/Performance")
            try run("rm -rf Packages/Vapor-*/Sources/Generator")
        } catch {
            print("Failed to remove extra schemes")
        }

        var flags = args
        if args.contains("--release") {
            flags = flags.filter { $0 != "--release" }
            flags.append("-c release")
        }
        do {
            let buildFlags = flags.joined(separator: " ")
            try run("swift build \(buildFlags)")
        } catch Error.cancelled {
            fail("Build cancelled.")
        } catch {
            print()
            print("Need help getting your project to build?")
            print("Join our Slack where hundreds of contributors")
            print("are waiting to help: http://slack.qutheory.io")

            fail("Could not build project.")
        }
    }
}

extension Build {
  static var help: [String] {
    return [
      "build <module-name>",
      "Builds source files and links Vapor libs.",
      "Defaults to App/ folder structure."
    ]
  }
}

commands.append(Build)

// MARK: Run

struct Run: Command {
    static let id = "run"
    static func execute(with args: [String], in directory: String) {
        print("Running...")
        do {
            var parameters = args
            let name = args.valueFor(argument: "name") ?? "App"
            parameters.remove { $0.hasPrefix("--name") }

            let folder = args.contains("--release") ? "release" : "debug"
            parameters.remove("--release")

            // All remaining arguments are passed on to app
            let passthroughArgs = args.joined(separator: " ")
            // TODO: Check that file exists
            try run(".build/\(folder)/\(name) \(passthroughArgs)")
        } catch Error.cancelled {
            fail("Run cancelled.")
        } catch {
            fail("Could not run project.")
        }
    }
}

extension Run {
  static var help: [String] {
    return [
      "runs executable built by vapor build.",
      "use --release for release configuration."
    ]
  }
}

commands.append(Run)

// MARK: New

struct New: Command {
    static let id = "new"

    static func execute(with args: [String], in directory: String) {
        guard let name = args.first else {
            print("Usage: \(directory) \(id) <project-name>")
            fail("Invalid number of arguments.")
        }

        let verbose = args.contains("--verbose")
        let curlArgs = verbose ? "" : "-s"
        let tarArgs = verbose ? "v" : ""

        do {
            let escapedName = "\"\(name)\"" // FIX: Doesn’t support names with quotes
            try run("mkdir \(escapedName)")

            print("Cloning example...")

            try run("curl -L \(curlArgs) https://github.com/qutheory/vapor-example/archive/master.tar.gz -o \(escapedName)/vapor-example.tar.gz")

            print("Unpacking...")

            try run("tar -\(tarArgs)xzf \(escapedName)/vapor-example.tar.gz --strip-components=1 --directory \(escapedName)")
            try run("rm \(escapedName)/vapor-example.tar.gz")
            #if os(OSX)
                try run("cd \(escapedName) && vapor xcode")
            #endif

            if commandExists("git") {
                print("Initializing git repository if necessary...")
                system("git init \(escapedName)")
                system("cd \(escapedName) && git add . && git commit -m \"initial vapor project setup\"")
                print()
            }

            print()
            printFancy(asciiArt)
            print()
            printFancy([
                "    Project \"\(name)\" has been created.",
                "Type `cd \(name)` to enter project directory",
                "                   Enjoy!",
            ])
            print()
            #if os(OSX)
                system("open \(escapedName)/*.xcodeproj")
            #endif
        } catch {
            fail("Could not clone repository")
        }
    }
}

extension New {
    static var help: [String] {
        return [
            "new <project-name>",
            "Clones the Vapor Example to a given",
            "folder name and initializes an empty",
            "Git repository inside it."
        ]
    }
}

commands.append(New)

// MARK: Self

extension SelfCommands {
    struct Install: Command {
        static let id = "install"

        static func execute(with args: [String], in directory: String) {
            do {
                try run("mv \(directory) /usr/local/bin/vapor")
                print("Vapor CLI installed.")
            } catch {
                print("Trying with 'sudo'.")
                do {
                    try run("sudo mv \(directory) /usr/local/bin/vapor")
                    print("Vapor CLI installed.")
                } catch {
                    fail("Could not move Vapor CLI to install location.")
                }
            }
        }

        static var help: [String] {
            return [
                "Moves the CLI into the bin so",
                "that it is available in the PATH"
            ]
        }
    }
}

extension SelfCommands {
    struct Update: Command {
        static let id = "update"

        static func execute(with args: [String], in directory: String) {
            let name = "vapor-cli.tmp"
            let quiet = args.contains("--verbose") ? "" : "-s"

            do {
                print("Downloading...")
                try run("curl -L \(quiet) cli.qutheory.io -o \(name)")
            } catch {
                fail("Could not download Vapor CLI.")
            }

            do {
                try run("chmod +x \(name)")
                try run("\(name) self install")
            } catch {
                fail("Could not update CLI.")
            }
        }

        static var help: [String] {
            return [
                "Downloads the latest version of",
                "the Vapor command line interface."
            ]
        }
    }
}

extension SelfCommands {
    struct Compile: Command {
        static let id = "compile"

        static func execute(with args: [String], in directory: String) {
            let source = "vapor-cli.swift"

            do {
                try run("cp \(directory) \(source)")
            } catch {
                fail("Could not copy source.")
            }

            print("Compiling...")

            let name = "vapor-cli.tmp"
            let compile = "swiftc \(source) -o \(name)"
            #if os(OSX)
                let cmd = "env SDKROOT=$(xcrun -show-sdk-path -sdk macosx) \(compile)"
            #else
                let cmd = compile
            #endif

            do {
                try run(cmd)
            } catch {
                fail("Could not compile.")
            }

            do {
                try run("chmod +x \(name)")
                try run("mv \(name) \(directory)")
            } catch {
                print("Trying with 'sudo'.")
                do {
                    try run("sudo mv \(name) \(directory)")
                } catch {
                    fail("Could not move Vapor CLI to install location.")
                }
            }

            do {
                try run("rm \(source)")
            } catch {

            }

            print("Vapor CLI compiled.")
        }

        static var help: [String] {
            return [
                "Compiles and caches the CLI",
                "to improve performance."
            ]
        }
    }
}<commit_msg>update compile logs<commit_after>#!/usr/bin/env swift

#if os(OSX)
    import Darwin
#else
    import Glibc
#endif

import Foundation

// MARK: Utilities

@noreturn func fail(_ message: String) {
    print()
    print("Error: \(message)")
    print("Note: Make sure you are using Swift 3.0 Preview 1")
    exit(1)
}

enum Error: ErrorProtocol { // Errors pertaining to running commands
    case system(Int32)
    case cancelled
    case terminalSize
}

let whiteSpace = [Character(" "), Character("\n"), Character("\t"), Character("\r")]

extension String {
    func trim(trimCharacters: [Character] = whiteSpace) -> String {
        // while characters
        var mutable = self
        while let next = mutable.characters.first where trimCharacters.contains(next) {
            mutable.remove(at: mutable.startIndex)
        }
        while let next = mutable.characters.last where trimCharacters.contains(next) {
            mutable.remove(at: mutable.index(before: mutable.endIndex))
        }
        return mutable
    }
}

func runWithOutput(_ command: String) throws -> String { // Command needs to use the absolute path for the executable
    // Run the command
    let fp = popen(command, "r")
    
    defer {
        pclose(fp)
    }
    
    if let fp = fp {
        // Get the output of the command
        let pathSize: Int32 = 1035
        let path : UnsafeMutablePointer<Int8> = UnsafeMutablePointer(allocatingCapacity: Int(pathSize))
        var output = ""
        while fgets(path, pathSize - 1, fp) != nil {
            output += String(cString: path)
        }
        
        return output
    } else {
        throw Error.system(1)
    }
}

func run(_ command: String) throws {
    let result = system(command)

    if result == 2 {
        throw Error.cancelled
    } else if result != 0 {
        throw Error.system(result)
    }
}

func passes(_ command: String) -> Bool {
    return system(command) == 0
}

func getInput() -> String {
    return readLine(strippingNewline: true) ?? ""
}

func commandExists(_ command: String) -> Bool {
    return system("hash \(command) 2>/dev/null") == 0
}

func fileExists(_ fileName: String) -> Bool {
    return system("ls \(fileName) > /dev/null 2>&1") == 0
}

func gitHistoryIsClean() -> Bool {
    return system("test -z \"$(git status --porcelain)\" || exit 1") == 0
}

func readPackageSwiftFile() -> String {
    let file = "./Package.swift"
    do {
        return try String(contentsOfFile: file)
    } catch {
        print()
        print("Unable to find Package.swift")
        print("Make sure you've run `vapor new` or setup your Swift project manually")
        fail("")
    }
}

func extractPackageName(from packageFile: String) -> String {
    let packageName = packageFile
        .components(separatedBy: "\n")
        .lazy
        .map { $0.trim() }
        .filter { $0.hasPrefix("name") }
        .first?
        .components(separatedBy: "\"")
        .lazy
        .filter { !$0.hasPrefix("name") }
        .first

    guard let name = packageName else {
        fail("Unable to extract package name")
    }

    return name
}

func getPackageName() -> String {
    let packageFile = readPackageSwiftFile()
    let packageName = extractPackageName(from: packageFile)
    return packageName
}

func terminalSize() throws -> (width: Int, height: Int) {
    // Get the columns and lines from tput
    let tput = "/usr/bin/tput"
    let cols = try runWithOutput("\(tput) cols").trim(trimCharacters: ["\n"])
    let lines = try runWithOutput("\(tput) lines").trim(trimCharacters: ["\n"])
    
    if let cols = Int(cols), lines = Int(lines) {
        return (cols, lines)
    } else {
        throw Error.terminalSize
    }
}

enum ANSIColor: String {
    case black = "\u{001B}[0;30m"
    case red = "\u{001B}[0;31m"
    case green = "\u{001B}[0;32m"
    case yellow = "\u{001B}[0;33m"
    case blue = "\u{001B}[0;34m"
    case magenta = "\u{001B}[0;35m"
    case cyan = "\u{001B}[0;36m"
    case white = "\u{001B}[0;37m"
    case reset = "\u{001B}[0;0m"
}

func printFancy(_ strings: [String]) {
    printFancy(strings.joined(separator: "\n"))
}

func printFancy(_ string: String) {
    let centered: String
    do {
        let size = try terminalSize()
        centered = string.centerTextBlock(width: size.width)
    } catch {
        centered = string        
    }

    let fancy = centered.colored(with: [
        "*": .magenta, 
        "~": .blue, 
        "+": .cyan, // Droplet
        "_": .magenta, 
        "/": .magenta, 
        "\\": .magenta, 
        "|": .magenta, 
        "-": .magenta, 
        ")": .magenta // Title
    ])

    print(fancy)
}

extension String {
    func centerTextBlock(width: Int, paddingCharacter: Character = " ") -> String {
        // Split the string into lines
        var lines = characters.split(separator: Character("\n")).map(String.init)
        
        // Make sure there's more than one line
        guard lines.count > 0 else {
            return ""
        }
        
        // Find the longest line
        var longestLine = 0
        for line in lines {
            if line.characters.count > longestLine {
                longestLine = line.characters.count
            }
        }
        
        // Calculate the padding and make sure it's greater than or equal to 0
        let padding = max(0, (width - longestLine) / 2)
        
        // Apply the padding to each line
        for i in 0..<lines.count {
            for _ in 0..<padding {
                lines[i].insert(paddingCharacter, at: startIndex)
            }
        }
        
        return lines.joined(separator: "\n")
    }
    
    #if os(Linux)
        func hasPrefix(_ str: String) -> Bool {
            let strGen = str.characters.makeIterator()
            let selfGen = self.characters.makeIterator()
            let seq = zip(strGen, selfGen)
            for (lhs, rhs) in seq where lhs != rhs {
                    return false
            }
            return true
        }

        func hasSuffix(_ str: String) -> Bool {
            let strGen = str.characters.reversed().makeIterator()
            let selfGen = self.characters.reversed().makeIterator()
            let seq = zip(strGen, selfGen)
            for (lhs, rhs) in seq where lhs != rhs {
                    return false
            }
            return true
        }
    #endif

    func colored(with colors: [Character: ANSIColor], default defaultColor: ANSIColor = .reset) -> String {
        // Check the string is long enough
        guard characters.count > 0 else {
            return ""
        }
        
        // Create a new string
        var newString = ""
        
        // Add the string to the new string and color it
        var currentColor: ANSIColor = defaultColor
        for character in characters {
            // Check if there is a new color for this character than the one before
            if (colors[character] ?? defaultColor) != currentColor {
                currentColor = colors[character] ?? defaultColor // Update the current color
                newString += currentColor.rawValue // Add the color the new string
            }
            
            newString += String(character) // Add the character to the string
        }
        
        // Reset the colors
        newString += ANSIColor.reset.rawValue
        
        return newString
    }

    func colored(with color: ANSIColor) -> String {
        return color.rawValue + self + ANSIColor.reset.rawValue
    }
}

extension Sequence where Iterator.Element == String {
    func valueFor(argument name: String) -> String? {
        for argument in self where argument.hasPrefix("--\(name)=") {
            return argument.characters.split(separator: "=").last.flatMap(String.init)
        }
        return nil
    }
}

extension Array where Element: Equatable {
    mutating func remove(_ element: Element) {
        self = self.filter { $0 != element }
    }

    mutating func remove(matching: (Element) -> Bool) {
        self = self.filter { !matching($0) }
    }
}


let asciiArt: [String] = [
    "               **",
    "             **~~**",
    "           **~~~~~~**",
    "         **~~~~~~~~~~**",
    "       **~~~~~~~~~~~~~~**",
    "     **~~~~~~~~~~~~~~~~~~**",
    "   **~~~~~~~~~~~~~~~~~~~~~~**",
    "  **~~~~~~~~~~~~~~~~~~~~~~~~**",
    " **~~~~~~~~~~~~~~~~~~~~~~~~~~**",
    "**~~~~~~~~~~~~~~~~~~~~~~~~~~~~**",
    "**~~~~~~~~~~~~~~~~~~~~~~~~~~~~**",
    "**~~~~~~~~~~~~~~~~~~~~~++++~~~**",
    " **~~~~~~~~~~~~~~~~~~~++++~~~**",
    "  ***~~~~~~~~~~~~~~~++++~~~***",
    "    ****~~~~~~~~~~++++~~****",
    "       *****~~~~~~~~~*****",
    "          *************",
    " ",
    " _       __    ___   ___   ___",
    "\\ \\  /  / /\\  | |_) / / \\ | |_)",
    " \\_\\/  /_/--\\ |_|   \\_\\_/ |_| \\",
    "   a web framework for Swift",
    " "
]


// MARK: Command

protocol Command {
    static var id: String { get }
    static var help: [String] { get }

    static var dependencies: [String] { get }
    static var subCommands: [Command.Type] { get }
    static func execute(with args: [String], in directory: String)
}

extension Command {
    static var dependencies: [String] { return [] }
    static var help: [String] { return [] }
}

// sub command related methods
extension Command {
    static var subCommands: [Command.Type] { return [] }

    static func subCommand(forId id: String) -> Command.Type? {
        return subCommands.lazy.filter { $0.id == id }.first
    }

    static func executeSubCommand(with args: [String], in directory: String) {
        var iterator = args.makeIterator()
        guard let cmdId = iterator.next() else {
            fail("\(id) requires a sub command:\n" + description)
        }
        guard let subcommand = subCommand(forId: cmdId) else {
            fail("Unknown \(id) subcommand '\(cmdId)':\n" + description)
        }
        let passthroughArgs = Array(iterator)
        subcommand.execute(with: passthroughArgs, in: directory)
    }
}

extension Command {
    static var description: String {
        // Sub Commands
        let subCommandRows: [String] = subCommands.map { subCommand in
            var output = "      \(subCommand.id.colored(with: .blue)):" 

            if subCommand.help.count > 0 {
                output += "\n"
                output += subCommand.help.map { row in 
                    return "          \(row)"
                }.joined(separator: "\n")
                output += "\n"
            }

            return output
        }
        let subCommandOutput = "\n" + subCommandRows.joined(separator: "\n")

        // Command
        var output = "  \(id.colored(with: .magenta)):"

        if help.count > 0 {
            output += "\n"

            output += help.map { row in
                return "      \(row)"
            }.joined(separator: "\n")

            output += "\n"
        }

        output += subCommandOutput

        return output
    }
}

extension Command {
    static func assertDependenciesSatisfied() {
        for dependency in dependencies where !commandExists(dependency) {
            fail("\(id) requires \(dependency)")
        }
    }
}

// MARK: Tree

var commands: [Command.Type] = []

func getCommand(id: String) -> Command.Type? {
    return commands
        .lazy
        .filter { $0.id == id }
        .first
}

// MARK: Help

struct Help: Command {
    static let id = "help"
    static func execute(with args: [String], in directory: String) {
        print("Usage: \(directory) [\(commands.map({ $0.id }).joined(separator: "|"))]")

        var help = "\nAvailable Commands:\n\n"
        help += commands
            .map { cmd in cmd.description }//"  \(cmd.id):\n\(cmd.description)\n"}
            .joined(separator: "\n")
        help += "\n"
        print(help)

        print("Community:")
        print("    Join our Slack if you have questions,")
        print("    need help, or want to contribute.")
        print("    http://slack.qutheory.io")
        print()
    }
}

commands.append(Help)

// MARK: Clean

struct Clean: Command {
    static let id = "clean"
    static func execute(with args: [String], in directory: String) {
        guard args.isEmpty else {
            fail("\(id) doesn't take any additional parameters")
        }

        do {
            try run("rm -rf Packages .build")
            print("Cleaned.")
        } catch {
            fail("Could not clean.")
        }
    }
}

commands.append(Clean)

// MARK: Build

struct Build: Command {
    static let id = "build"
    static func execute(with args: [String], in directory: String) {
        do {
            try run("swift package fetch")
        } catch Error.cancelled {
            fail("Fetch cancelled")
        } catch {
            fail("Could not fetch dependencies.")
        }

        do {
            try run("rm -rf Packages/Vapor-*/Sources/Development")
            try run("rm -rf Packages/Vapor-*/Sources/Performance")
            try run("rm -rf Packages/Vapor-*/Sources/Generator")
        } catch {
            print("Failed to remove extra schemes")
        }

        var flags = args
        if args.contains("--release") {
            flags = flags.filter { $0 != "--release" }
            flags.append("-c release")
        }
        do {
            let buildFlags = flags.joined(separator: " ")
            try run("swift build \(buildFlags)")
        } catch Error.cancelled {
            fail("Build cancelled.")
        } catch {
            print()
            print("Need help getting your project to build?")
            print("Join our Slack where hundreds of contributors")
            print("are waiting to help: http://slack.qutheory.io")

            fail("Could not build project.")
        }
    }
}

extension Build {
  static var help: [String] {
    return [
      "build <module-name>",
      "Builds source files and links Vapor libs.",
      "Defaults to App/ folder structure."
    ]
  }
}

commands.append(Build)

// MARK: Run

struct Run: Command {
    static let id = "run"
    static func execute(with args: [String], in directory: String) {
        print("Running...")
        do {
            var parameters = args
            let name = args.valueFor(argument: "name") ?? "App"
            parameters.remove { $0.hasPrefix("--name") }

            let folder = args.contains("--release") ? "release" : "debug"
            parameters.remove("--release")

            // All remaining arguments are passed on to app
            let passthroughArgs = args.joined(separator: " ")
            // TODO: Check that file exists
            try run(".build/\(folder)/\(name) \(passthroughArgs)")
        } catch Error.cancelled {
            fail("Run cancelled.")
        } catch {
            fail("Could not run project.")
        }
    }
}

extension Run {
  static var help: [String] {
    return [
      "runs executable built by vapor build.",
      "use --release for release configuration."
    ]
  }
}

commands.append(Run)

// MARK: New

struct New: Command {
    static let id = "new"

    static func execute(with args: [String], in directory: String) {
        guard let name = args.first else {
            print("Usage: \(directory) \(id) <project-name>")
            fail("Invalid number of arguments.")
        }

        let verbose = args.contains("--verbose")
        let curlArgs = verbose ? "" : "-s"
        let tarArgs = verbose ? "v" : ""

        do {
            let escapedName = "\"\(name)\"" // FIX: Doesn’t support names with quotes
            try run("mkdir \(escapedName)")

            print("Cloning example...")

            try run("curl -L \(curlArgs) https://github.com/qutheory/vapor-example/archive/master.tar.gz -o \(escapedName)/vapor-example.tar.gz")

            print("Unpacking...")

            try run("tar -\(tarArgs)xzf \(escapedName)/vapor-example.tar.gz --strip-components=1 --directory \(escapedName)")
            try run("rm \(escapedName)/vapor-example.tar.gz")
            #if os(OSX)
                try run("cd \(escapedName) && vapor xcode")
            #endif

            if commandExists("git") {
                print("Initializing git repository if necessary...")
                system("git init \(escapedName)")
                system("cd \(escapedName) && git add . && git commit -m \"initial vapor project setup\"")
                print()
            }

            print()
            printFancy(asciiArt)
            print()
            printFancy([
                "    Project \"\(name)\" has been created.",
                "Type `cd \(name)` to enter project directory",
                "                   Enjoy!",
            ])
            print()
            #if os(OSX)
                system("open \(escapedName)/*.xcodeproj")
            #endif
        } catch {
            fail("Could not clone repository")
        }
    }
}

extension New {
    static var help: [String] {
        return [
            "new <project-name>",
            "Clones the Vapor Example to a given",
            "folder name and initializes an empty",
            "Git repository inside it."
        ]
    }
}

commands.append(New)

// MARK: Self

extension SelfCommands {
    struct Install: Command {
        static let id = "install"

        static func execute(with args: [String], in directory: String) {
            do {
                try run("mv \(directory) /usr/local/bin/vapor")
                print("Vapor CLI installed.")
            } catch {
                print("Trying with 'sudo'.")
                do {
                    try run("sudo mv \(directory) /usr/local/bin/vapor")
                    print("Vapor CLI installed.")
                } catch {
                    fail("Could not move Vapor CLI to install location.")
                }
            }
        }

        static var help: [String] {
            return [
                "Moves the CLI into the bin so",
                "that it is available in the PATH"
            ]
        }
    }
}

extension SelfCommands {
    struct Update: Command {
        static let id = "update"

        static func execute(with args: [String], in directory: String) {
            let name = "vapor-cli.tmp"
            let quiet = args.contains("--verbose") ? "" : "-s"

            do {
                print("Downloading...")
                try run("curl -L \(quiet) cli.qutheory.io -o \(name)")
            } catch {
                fail("Could not download Vapor CLI.")
            }

            do {
                try run("chmod +x \(name)")
                try run("\(name) self install")
            } catch {
                fail("Could not update CLI.")
            }
        }

        static var help: [String] {
            return [
                "Downloads the latest version of",
                "the Vapor command line interface."
            ]
        }
    }
}

extension SelfCommands {
    struct Compile: Command {
        static let id = "compile"

        static func execute(with args: [String], in directory: String) {
            let source = "vapor-cli.swift"

            do {
                try run("cp \(directory) \(source)")
            } catch {
                fail("Could not copy source.")
            }

            print("Compiling...")

            let name = "vapor-cli.tmp"
            let compile = "swiftc \(source) -o \(name)"
            #if os(OSX)
                let cmd = "env SDKROOT=$(xcrun -show-sdk-path -sdk macosx) \(compile)"
            #else
                let cmd = compile
            #endif

            do {
                try run(cmd)
            } catch {
                fail("Could not compile.")
            }

            do {
                try run("chmod +x \(name)")
                try run("mv \(name) \(directory)")
            } catch {
                print("Trying with sudo...")
                do {
                    try run("sudo mv \(name) \(directory)")
                } catch {
                    fail("Could not move Vapor CLI to install location.")
                }
            }

            do {
                try run("rm \(source)")
            } catch {

            }

            print("Vapor CLI compiled.")
        }

        static var help: [String] {
            return [
                "Compiles and caches the CLI",
                "to improve performance."
            ]
        }
    }
}
{'fraction_non_alphanumeric': 0.1406486962477374, 'fraction_numerical': 0.004843207279487305, 'mean_word_length': 1.6680806630555374, 'pattern_counts': {'":': 18, '<': 15, '<?xml version=': 0, '>': 67, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2789508', 'n_tokens_mistral': 11836, 'n_tokens_neox': 11266, 'n_words': 3186}