{"action":"created","comment":{"url":"https://api.github.com/repos/qutheory/vapor/pulls/comments/64050942","id":64050942,"diff_hunk":"@@ -1,258 +1,280 @@\n-/**\n-    Parses and interprets configuration files\n-    included under Config in the working directory.\n+import PathIndexable\n+import Foundation\n \n-    Files stored in the Config directory can be accessed\n-    via `app.config.get(\"filename.property\")`.\n+private struct JsonFile {\n+    let name: String\n+    let json: Json\n \n-    For example, a file named `Config/app.json` containing\n-    `{\"port\": 80}` can be accessed with `app.config.get(\"app.port\")`.\n-    To override certain configurations for a given environment,\n-    create a file with the same name in a subdirectory of the environment.\n-    For example, a file named `Config/production/app.json` would override\n-    any properties in `Config/app.json`.\n+    private static let suffix = \".json\"\n \n-    Finally, Vapor supports sensitive environment specific information, such\n-    as API keys, to be stored in a special configuration file at `Config/.env.json`.\n-    This file should be included in the `.gitignore` by default so that\n-    sensitive information does not get added to version control.\n-*/\n-public class Config {\n-    /**\n-        The internal store of configuration options\n-        backed by `Json`\n-     */\n-    private var repository: [String: Json]\n-\n-    public enum Error: ErrorProtocol {\n-        case NoFileFound\n-        case NoValueFound\n+    init(name: String, json: Json) {\n+        if\n+            let nameSequence = name.characters.split(separator: \".\").first\n+            where name.hasSuffix(JsonFile.suffix)\n+        {\n+            self.name = String(nameSequence)\n+        } else {\n+            self.name = name\n+        }\n+        self.json = json\n     }\n+}\n \n-    /**\n-        Creates an instance of `Config` with an\n-        optional starting repository of information.\n-        The application is required to detect environment.\n-    */\n-    public init(repository: [String: Json] = [:], application: Application? = nil) {\n-        self.repository = repository\n+private struct ConfigDirectory {\n+    let name: String\n+    let files: [JsonFile]\n \n-        if let application = application {\n-            populate(application)\n-        }\n+    subscript(_ name: String, _ paths: [PathIndex]) -> Json? {\n+        return files\n+            .lazy\n+            .filter { file in\n+                file.name == name\n+            }\n+            .flatMap { file in file.json[paths] }\n+            .first\n     }\n+}\n \n-    /**\n-        Returns whether this instance of `Config` contains the key\n-     */\n-    public func has(_ keyPath: String) -> Bool {\n-        let result: Node? = try? get(keyPath)\n-        return result != nil\n+private struct PrioritizedDirectoryQueue {\n+    let directories: [ConfigDirectory]\n+\n+    subscript(_ fileName: String, indexes: [PathIndex]) -> Json? {\n+        return directories\n+            .lazy\n+            .flatMap { directory in return directory[fileName, indexes] }\n+            .first\n     }\n+}\n \n-    /**\n-        Returns the generic Json representation for an item at a given path or throws\n-     */\n-    public func get(_ keyPath: String) throws -> Node {\n-        var keys = keyPath.keys\n-        guard let json: Json = repository[keys.removeFirst()] else {\n-            throw Error.NoFileFound\n+extension FileManager {\n+    private static func loadDirectory(_ path: String) -> ConfigDirectory? {\n+        guard let directoryName = path.components(separatedBy: \"/\").last else {\n+            return nil\n         }\n-\n-        var node: Node? = json\n-\n-        for key in keys {\n-            node = node?.object?[key]\n+        guard let contents = try? FileManager.contentsOfDirectory(path) else {\n+            return nil\n         }\n \n-        guard let result = node else {\n-            throw Error.NoValueFound\n+        var jsonFiles: [JsonFile] = []\n+        for file in contents where file.hasSuffix(\".json\") {\n+            guard let name = file.components(separatedBy: \"/\").last else {\n+                continue\n+            }\n+            guard let json = try? loadJson(file) else {\n+                continue\n+            }\n+\n+            let jsonFile = JsonFile(name: name, json: json)\n+            jsonFiles.append(jsonFile)\n         }\n \n-        return result\n+        let directory = ConfigDirectory(name: directoryName, files: jsonFiles)\n+        return directory\n     }\n \n-    /**\n-        Returns the value for a given type from the Config or throws\n-     */\n-    public func get<T: NodeInitializable>(_ keyPath: String) throws -> T {\n-        let result: Node = try get(keyPath)\n-        return try T.make(with: result)\n+    private static func loadJson(_ path: String) throws -> Json {\n+        let bytes = try FileManager.readBytesFromFile(path)\n+        return try Json.deserialize(bytes)\n     }\n+}\n \n+extension Process {\n+    private static func makeCLIConfig() -> ConfigDirectory {\n+        let configArgs = NSProcessInfo.processInfo().arguments.filter { $0.hasPrefix(\"--config:\") }\n \n-    /**\n-        Returns the result of `get(key: String)` but with a `String` fallback for `nil` cases\n-     */\n-    public func get<T: NodeInitializable>(_ keyPath: String, _ fallback: T) -> T {\n-        let string: T? = try? get(keyPath)\n-        return string ?? fallback\n-    }\n+        // [FileName: Json]\n+        var directory: [String: Json] = [:]\n \n+        for arg in configArgs {\n+            guard let (key, value) = parseArgument(arg) else {\n+                continue\n+            }\n \n-    /**\n-        Temporarily sets a value for a given key path\n-     */\n-    public func set(_ value: Json, forKeyPath keyPath: String) {\n-        var keys = keyPath.keys\n-        let group = keys.removeFirst()\n+            guard let (file, path) = parseConfigKey(key) else {\n+                continue\n+            }\n \n-        if keys.count == 0 {\n-            repository[group] = value\n-        } else {\n-            repository[group]?.set(value, keys: keyPath.keys)\n+            var js = directory[file] ?? .object([:])\n+            js[path] = .string(value)\n+            directory[file] = js\n         }\n+\n+        let jsonFiles = directory.map { fileName, json in JsonFile(name: fileName, json: json) }\n+        let config = ConfigDirectory(name: \"cli\", files: jsonFiles)\n+        return config\n     }\n \n-    /**\n-        Calls populate() in a convenient non-throwing manner\n-     */\n-    public func populate(_ application: Application) -> Bool {\n-        let configDir = application.workDir + \"Config\"\n-\n-        if FileManager.fileAtPath(configDir).exists {\n-            do {\n-                try populate(configDir, application: application)\n-                return true\n-            } catch {\n-                Log.error(\"Unable to populate config: \\(error)\")\n-                return false\n-            }\n-        } else {\n-            return false\n+    private static func parseArgument(_ arg: String) -> (key: String, value: String)? {\n+        let info = arg\n+            .characters\n+            .split(separator: \"=\",\n+                   maxSplits: 1,\n+                   omittingEmptySubsequences: true)\n+            .map(String.init)\n+\n+        guard info.count == 2, let key = info.first, let value = info.last else {\n+            Log.info(\"Unable to parse possible config argument: \\(arg)\")\n+            return nil\n         }\n+\n+        return (key, value)\n     }\n \n+    private static func parseConfigKey(_ key: String) -> (file: String, path: [PathIndex])? {\n+        // --config:app.port\n+        // expect [--config, app.port]\n+        let paths = key\n+            .characters\n+            .split(separator: \":\",\n+                   maxSplits: 1,\n+                   omittingEmptySubsequences: true)\n+            .map(String.init)\n+\n+        guard\n+            paths.count == 2,\n+            var keyPaths = paths.last?.components(separatedBy: \".\"),\n+            let fileName = keyPaths.first\n+            // first argument is file name, subsequent args are actual path\n+            //\n+            where keyPaths.count > 1\n+            else {\n+                Log.info(\"Unable to parse possible config path: \\(key)\")\n+                return nil\n+            }\n \n+        // first argument is file name, subsequent arguments are paths\n+        keyPaths.remove(at: 0)\n \n-    /**\n-        Attempts to populate the internal configuration store\n-     */\n-    public func populate(_ path: String, application: Application) throws {\n-        var path = path.finish(\"/\")\n-        var files = [String: [String]]()\n+        return (fileName, keyPaths.map { $0 as PathIndex })\n+    }\n+}\n \n-        // Populate config files by environment\n-        try populateConfigFiles(&files, in: path)\n+/**\n+    Parses and interprets configuration files\n+    included under Config in the working directory.\n \n-        for env in application.environment.description.keys {\n-            path += env + \"/\"\n+    Files stored in the Config directory can be accessed\n+    via `app.config[\"filename\", \"property\"]`.\n \n-            if FileManager.fileAtPath(path).exists {\n-                try populateConfigFiles(&files, in: path)\n-            }\n-        }\n-        // Loop through files and merge config upwards so the\n-        // environment always overrides the base config\n-        //\n-        //\n-        // The isEmpty check is a workaround for the Linux system and is necessary until\n-        // an alternative solution is fixed, or it's confirmed appropriate\n-        // This is duplicated below in `populateConfigFiles`. just doubling down.\n-        for (group, files) in files where !group.isEmpty {\n-            if group == \".env\" {\n-                // .env is handled differently below\n-                continue\n-            }\n+    For example, a file named `Config/app.json` containing\n+    `{\"port\": 80}` can be accessed with `app.config[\"app\" \"port\"].int`.\n+    To override certain configurations for a given environment,\n+    create a file with the same name in a subdirectory of the environment.\n+    For example, a file named `Config/production/app.json` would override\n+    any properties in `Config/app.json` when the app is in production mode.\n \n-            for file in files {\n-                let bytes = try FileManager.readBytesFromFile(file)\n-                let json = try Json(Data(bytes))\n+    Finally, Vapor supports sensitive environment specific information, such\n+    as API keys, to be stored in a special configuration folder at `Config/secrets`.\n+    This folder should be included in the `.gitignore` by default so that\n+    sensitive information does not get added to version control. ","path":"Sources/Vapor/Config/Config.swift","position":294,"original_position":294,"commit_id":"ef0aa185ed83c5ace372c2ed8242eda9c18d0b28","original_commit_id":"ef0aa185ed83c5ace372c2ed8242eda9c18d0b28","user":{"login":"houndci-bot","id":6697940,"avatar_url":"https://avatars.githubusercontent.com/u/6697940?v=3","gravatar_id":"","url":"https://api.github.com/users/houndci-bot","html_url":"https://github.com/houndci-bot","followers_url":"https://api.github.com/users/houndci-bot/followers","following_url":"https://api.github.com/users/houndci-bot/following{/other_user}","gists_url":"https://api.github.com/users/houndci-bot/gists{/gist_id}","starred_url":"https://api.github.com/users/houndci-bot/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/houndci-bot/subscriptions","organizations_url":"https://api.github.com/users/houndci-bot/orgs","repos_url":"https://api.github.com/users/houndci-bot/repos","events_url":"https://api.github.com/users/houndci-bot/events{/privacy}","received_events_url":"https://api.github.com/users/houndci-bot/received_events","type":"User","site_admin":false},"body":"Trailing Whitespace Violation: Lines should not have trailing whitespace. (trailing_whitespace)","created_at":"2016-05-20T14:35:18Z","updated_at":"2016-05-20T14:35:18Z","html_url":"https://github.com/qutheory/vapor/pull/287#discussion_r64050942","pull_request_url":"https://api.github.com/repos/qutheory/vapor/pulls/287","_links":{"self":{"href":"https://api.github.com/repos/qutheory/vapor/pulls/comments/64050942"},"html":{"href":"https://github.com/qutheory/vapor/pull/287#discussion_r64050942"},"pull_request":{"href":"https://api.github.com/repos/qutheory/vapor/pulls/287"}}},"pull_request":{"url":"https://api.github.com/repos/qutheory/vapor/pulls/287","id":70633394,"html_url":"https://github.com/qutheory/vapor/pull/287","diff_url":"https://github.com/qutheory/vapor/pull/287.diff","patch_url":"https://github.com/qutheory/vapor/pull/287.patch","issue_url":"https://api.github.com/repos/qutheory/vapor/issues/287","number":287,"state":"open","locked":false,"title":"config hierarchy ","user":{"login":"LoganWright","id":5750489,"avatar_url":"https://avatars.githubusercontent.com/u/5750489?v=3","gravatar_id":"","url":"https://api.github.com/users/LoganWright","html_url":"https://github.com/LoganWright","followers_url":"https://api.github.com/users/LoganWright/followers","following_url":"https://api.github.com/users/LoganWright/following{/other_user}","gists_url":"https://api.github.com/users/LoganWright/gists{/gist_id}","starred_url":"https://api.github.com/users/LoganWright/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/LoganWright/subscriptions","organizations_url":"https://api.github.com/users/LoganWright/orgs","repos_url":"https://api.github.com/users/LoganWright/repos","events_url":"https://api.github.com/users/LoganWright/events{/privacy}","received_events_url":"https://api.github.com/users/LoganWright/received_events","type":"User","site_admin":false},"body":"#279 ","created_at":"2016-05-19T03:52:46Z","updated_at":"2016-05-20T14:35:18Z","closed_at":null,"merged_at":null,"merge_commit_sha":"d0f4dc575a60282350d6e949689aa2460b390244","assignee":{"login":"LoganWright","id":5750489,"avatar_url":"https://avatars.githubusercontent.com/u/5750489?v=3","gravatar_id":"","url":"https://api.github.com/users/LoganWright","html_url":"https://github.com/LoganWright","followers_url":"https://api.github.com/users/LoganWright/followers","following_url":"https://api.github.com/users/LoganWright/following{/other_user}","gists_url":"https://api.github.com/users/LoganWright/gists{/gist_id}","starred_url":"https://api.github.com/users/LoganWright/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/LoganWright/subscriptions","organizations_url":"https://api.github.com/users/LoganWright/orgs","repos_url":"https://api.github.com/users/LoganWright/repos","events_url":"https://api.github.com/users/LoganWright/events{/privacy}","received_events_url":"https://api.github.com/users/LoganWright/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/qutheory/vapor/milestones/2","html_url":"https://github.com/qutheory/vapor/milestones/0.9","labels_url":"https://api.github.com/repos/qutheory/vapor/milestones/2/labels","id":1753200,"number":2,"title":"0.9","description":"","creator":{"login":"tannernelson","id":1342803,"avatar_url":"https://avatars.githubusercontent.com/u/1342803?v=3","gravatar_id":"","url":"https://api.github.com/users/tannernelson","html_url":"https://github.com/tannernelson","followers_url":"https://api.github.com/users/tannernelson/followers","following_url":"https://api.github.com/users/tannernelson/following{/other_user}","gists_url":"https://api.github.com/users/tannernelson/gists{/gist_id}","starred_url":"https://api.github.com/users/tannernelson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tannernelson/subscriptions","organizations_url":"https://api.github.com/users/tannernelson/orgs","repos_url":"https://api.github.com/users/tannernelson/repos","events_url":"https://api.github.com/users/tannernelson/events{/privacy}","received_events_url":"https://api.github.com/users/tannernelson/received_events","type":"User","site_admin":false},"open_issues":15,"closed_issues":1,"state":"open","created_at":"2016-05-07T17:59:01Z","updated_at":"2016-05-20T14:18:57Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/qutheory/vapor/pulls/287/commits","review_comments_url":"https://api.github.com/repos/qutheory/vapor/pulls/287/comments","review_comment_url":"https://api.github.com/repos/qutheory/vapor/pulls/comments{/number}","comments_url":"https://api.github.com/repos/qutheory/vapor/issues/287/comments","statuses_url":"https://api.github.com/repos/qutheory/vapor/statuses/ef0aa185ed83c5ace372c2ed8242eda9c18d0b28","head":{"label":"qutheory:config-reprise","ref":"config-reprise","sha":"ef0aa185ed83c5ace372c2ed8242eda9c18d0b28","user":{"login":"qutheory","id":17364220,"avatar_url":"https://avatars.githubusercontent.com/u/17364220?v=3","gravatar_id":"","url":"https://api.github.com/users/qutheory","html_url":"https://github.com/qutheory","followers_url":"https://api.github.com/users/qutheory/followers","following_url":"https://api.github.com/users/qutheory/following{/other_user}","gists_url":"https://api.github.com/users/qutheory/gists{/gist_id}","starred_url":"https://api.github.com/users/qutheory/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/qutheory/subscriptions","organizations_url":"https://api.github.com/users/qutheory/orgs","repos_url":"https://api.github.com/users/qutheory/repos","events_url":"https://api.github.com/users/qutheory/events{/privacy}","received_events_url":"https://api.github.com/users/qutheory/received_events","type":"Organization","site_admin":false},"repo":{"id":49910095,"name":"vapor","full_name":"qutheory/vapor","owner":{"login":"qutheory","id":17364220,"avatar_url":"https://avatars.githubusercontent.com/u/17364220?v=3","gravatar_id":"","url":"https://api.github.com/users/qutheory","html_url":"https://github.com/qutheory","followers_url":"https://api.github.com/users/qutheory/followers","following_url":"https://api.github.com/users/qutheory/following{/other_user}","gists_url":"https://api.github.com/users/qutheory/gists{/gist_id}","starred_url":"https://api.github.com/users/qutheory/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/qutheory/subscriptions","organizations_url":"https://api.github.com/users/qutheory/orgs","repos_url":"https://api.github.com/users/qutheory/repos","events_url":"https://api.github.com/users/qutheory/events{/privacy}","received_events_url":"https://api.github.com/users/qutheory/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/qutheory/vapor","description":"An elegant web framework for Swift that works on OS X and Ubuntu.","fork":false,"url":"https://api.github.com/repos/qutheory/vapor","forks_url":"https://api.github.com/repos/qutheory/vapor/forks","keys_url":"https://api.github.com/repos/qutheory/vapor/keys{/key_id}","collaborators_url":"https://api.github.com/repos/qutheory/vapor/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/qutheory/vapor/teams","hooks_url":"https://api.github.com/repos/qutheory/vapor/hooks","issue_events_url":"https://api.github.com/repos/qutheory/vapor/issues/events{/number}","events_url":"https://api.github.com/repos/qutheory/vapor/events","assignees_url":"https://api.github.com/repos/qutheory/vapor/assignees{/user}","branches_url":"https://api.github.com/repos/qutheory/vapor/branches{/branch}","tags_url":"https://api.github.com/repos/qutheory/vapor/tags","blobs_url":"https://api.github.com/repos/qutheory/vapor/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/qutheory/vapor/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/qutheory/vapor/git/refs{/sha}","trees_url":"https://api.github.com/repos/qutheory/vapor/git/trees{/sha}","statuses_url":"https://api.github.com/repos/qutheory/vapor/statuses/{sha}","languages_url":"https://api.github.com/repos/qutheory/vapor/languages","stargazers_url":"https://api.github.com/repos/qutheory/vapor/stargazers","contributors_url":"https://api.github.com/repos/qutheory/vapor/contributors","subscribers_url":"https://api.github.com/repos/qutheory/vapor/subscribers","subscription_url":"https://api.github.com/repos/qutheory/vapor/subscription","commits_url":"https://api.github.com/repos/qutheory/vapor/commits{/sha}","git_commits_url":"https://api.github.com/repos/qutheory/vapor/git/commits{/sha}","comments_url":"https://api.github.com/repos/qutheory/vapor/comments{/number}","issue_comment_url":"https://api.github.com/repos/qutheory/vapor/issues/comments{/number}","contents_url":"https://api.github.com/repos/qutheory/vapor/contents/{+path}","compare_url":"https://api.github.com/repos/qutheory/vapor/compare/{base}...{head}","merges_url":"https://api.github.com/repos/qutheory/vapor/merges","archive_url":"https://api.github.com/repos/qutheory/vapor/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/qutheory/vapor/downloads","issues_url":"https://api.github.com/repos/qutheory/vapor/issues{/number}","pulls_url":"https://api.github.com/repos/qutheory/vapor/pulls{/number}","milestones_url":"https://api.github.com/repos/qutheory/vapor/milestones{/number}","notifications_url":"https://api.github.com/repos/qutheory/vapor/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/qutheory/vapor/labels{/name}","releases_url":"https://api.github.com/repos/qutheory/vapor/releases{/id}","deployments_url":"https://api.github.com/repos/qutheory/vapor/deployments","created_at":"2016-01-18T22:37:52Z","updated_at":"2016-05-20T14:31:00Z","pushed_at":"2016-05-20T14:35:04Z","git_url":"git://github.com/qutheory/vapor.git","ssh_url":"git@github.com:qutheory/vapor.git","clone_url":"https://github.com/qutheory/vapor.git","svn_url":"https://github.com/qutheory/vapor","homepage":"qutheory.io","size":6813,"stargazers_count":3865,"watchers_count":3865,"language":"Swift","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":204,"mirror_url":null,"open_issues_count":45,"forks":204,"open_issues":45,"watchers":3865,"default_branch":"master"}},"base":{"label":"qutheory:indexable","ref":"indexable","sha":"8a10b70e80558cb6b0a90152adb9657a1c302ca2","user":{"login":"qutheory","id":17364220,"avatar_url":"https://avatars.githubusercontent.com/u/17364220?v=3","gravatar_id":"","url":"https://api.github.com/users/qutheory","html_url":"https://github.com/qutheory","followers_url":"https://api.github.com/users/qutheory/followers","following_url":"https://api.github.com/users/qutheory/following{/other_user}","gists_url":"https://api.github.com/users/qutheory/gists{/gist_id}","starred_url":"https://api.github.com/users/qutheory/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/qutheory/subscriptions","organizations_url":"https://api.github.com/users/qutheory/orgs","repos_url":"https://api.github.com/users/qutheory/repos","events_url":"https://api.github.com/users/qutheory/events{/privacy}","received_events_url":"https://api.github.com/users/qutheory/received_events","type":"Organization","site_admin":false},"repo":{"id":49910095,"name":"vapor","full_name":"qutheory/vapor","owner":{"login":"qutheory","id":17364220,"avatar_url":"https://avatars.githubusercontent.com/u/17364220?v=3","gravatar_id":"","url":"https://api.github.com/users/qutheory","html_url":"https://github.com/qutheory","followers_url":"https://api.github.com/users/qutheory/followers","following_url":"https://api.github.com/users/qutheory/following{/other_user}","gists_url":"https://api.github.com/users/qutheory/gists{/gist_id}","starred_url":"https://api.github.com/users/qutheory/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/qutheory/subscriptions","organizations_url":"https://api.github.com/users/qutheory/orgs","repos_url":"https://api.github.com/users/qutheory/repos","events_url":"https://api.github.com/users/qutheory/events{/privacy}","received_events_url":"https://api.github.com/users/qutheory/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/qutheory/vapor","description":"An elegant web framework for Swift that works on OS X and Ubuntu.","fork":false,"url":"https://api.github.com/repos/qutheory/vapor","forks_url":"https://api.github.com/repos/qutheory/vapor/forks","keys_url":"https://api.github.com/repos/qutheory/vapor/keys{/key_id}","collaborators_url":"https://api.github.com/repos/qutheory/vapor/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/qutheory/vapor/teams","hooks_url":"https://api.github.com/repos/qutheory/vapor/hooks","issue_events_url":"https://api.github.com/repos/qutheory/vapor/issues/events{/number}","events_url":"https://api.github.com/repos/qutheory/vapor/events","assignees_url":"https://api.github.com/repos/qutheory/vapor/assignees{/user}","branches_url":"https://api.github.com/repos/qutheory/vapor/branches{/branch}","tags_url":"https://api.github.com/repos/qutheory/vapor/tags","blobs_url":"https://api.github.com/repos/qutheory/vapor/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/qutheory/vapor/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/qutheory/vapor/git/refs{/sha}","trees_url":"https://api.github.com/repos/qutheory/vapor/git/trees{/sha}","statuses_url":"https://api.github.com/repos/qutheory/vapor/statuses/{sha}","languages_url":"https://api.github.com/repos/qutheory/vapor/languages","stargazers_url":"https://api.github.com/repos/qutheory/vapor/stargazers","contributors_url":"https://api.github.com/repos/qutheory/vapor/contributors","subscribers_url":"https://api.github.com/repos/qutheory/vapor/subscribers","subscription_url":"https://api.github.com/repos/qutheory/vapor/subscription","commits_url":"https://api.github.com/repos/qutheory/vapor/commits{/sha}","git_commits_url":"https://api.github.com/repos/qutheory/vapor/git/commits{/sha}","comments_url":"https://api.github.com/repos/qutheory/vapor/comments{/number}","issue_comment_url":"https://api.github.com/repos/qutheory/vapor/issues/comments{/number}","contents_url":"https://api.github.com/repos/qutheory/vapor/contents/{+path}","compare_url":"https://api.github.com/repos/qutheory/vapor/compare/{base}...{head}","merges_url":"https://api.github.com/repos/qutheory/vapor/merges","archive_url":"https://api.github.com/repos/qutheory/vapor/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/qutheory/vapor/downloads","issues_url":"https://api.github.com/repos/qutheory/vapor/issues{/number}","pulls_url":"https://api.github.com/repos/qutheory/vapor/pulls{/number}","milestones_url":"https://api.github.com/repos/qutheory/vapor/milestones{/number}","notifications_url":"https://api.github.com/repos/qutheory/vapor/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/qutheory/vapor/labels{/name}","releases_url":"https://api.github.com/repos/qutheory/vapor/releases{/id}","deployments_url":"https://api.github.com/repos/qutheory/vapor/deployments","created_at":"2016-01-18T22:37:52Z","updated_at":"2016-05-20T14:31:00Z","pushed_at":"2016-05-20T14:35:04Z","git_url":"git://github.com/qutheory/vapor.git","ssh_url":"git@github.com:qutheory/vapor.git","clone_url":"https://github.com/qutheory/vapor.git","svn_url":"https://github.com/qutheory/vapor","homepage":"qutheory.io","size":6813,"stargazers_count":3865,"watchers_count":3865,"language":"Swift","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":204,"mirror_url":null,"open_issues_count":45,"forks":204,"open_issues":45,"watchers":3865,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/qutheory/vapor/pulls/287"},"html":{"href":"https://github.com/qutheory/vapor/pull/287"},"issue":{"href":"https://api.github.com/repos/qutheory/vapor/issues/287"},"comments":{"href":"https://api.github.com/repos/qutheory/vapor/issues/287/comments"},"review_comments":{"href":"https://api.github.com/repos/qutheory/vapor/pulls/287/comments"},"review_comment":{"href":"https://api.github.com/repos/qutheory/vapor/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/qutheory/vapor/pulls/287/commits"},"statuses":{"href":"https://api.github.com/repos/qutheory/vapor/statuses/ef0aa185ed83c5ace372c2ed8242eda9c18d0b28"}}}}
{"actor":{"display_login":"houndci-bot"}}