{"action":"created","comment":{"url":"https://api.github.com/repos/glyptodon/guacamole-client/pulls/comments/28937717","id":28937717,"diff_hunk":"@@ -0,0 +1,159 @@\n+/*\n+ * Copyright (C) 2015 Glyptodon LLC\n+ *\n+ * Permission is hereby granted, free of charge, to any person obtaining a copy\n+ * of this software and associated documentation files (the \"Software\"), to deal\n+ * in the Software without restriction, including without limitation the rights\n+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n+ * copies of the Software, and to permit persons to whom the Software is\n+ * furnished to do so, subject to the following conditions:\n+ *\n+ * The above copyright notice and this permission notice shall be included in\n+ * all copies or substantial portions of the Software.\n+ *\n+ * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n+ * THE SOFTWARE.\n+ */\n+\n+package org.glyptodon.guacamole.net.basic.rest.language;\n+\n+import java.io.IOException;\n+import java.io.InputStream;\n+import java.util.Collections;\n+import java.util.HashMap;\n+import java.util.Map;\n+import java.util.Set;\n+import java.util.regex.Matcher;\n+import java.util.regex.Pattern;\n+import javax.servlet.ServletContext;\n+import javax.ws.rs.GET;\n+import javax.ws.rs.Path;\n+import javax.ws.rs.Produces;\n+import javax.ws.rs.QueryParam;\n+import javax.ws.rs.core.Context;\n+import javax.ws.rs.core.MediaType;\n+import org.codehaus.jackson.JsonNode;\n+import org.codehaus.jackson.map.ObjectMapper;\n+import org.glyptodon.guacamole.GuacamoleException;\n+import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;\n+import org.slf4j.Logger;\n+import org.slf4j.LoggerFactory;\n+\n+\n+/**\n+ * A REST Service for handling the listing of languages.\n+ * \n+ * @author James Muehlner\n+ */\n+@Path(\"/languages\")\n+@Produces(MediaType.APPLICATION_JSON)\n+public class LanguageRESTService {\n+\n+    /**\n+     * Logger for this class.\n+     */\n+    private final Logger logger = LoggerFactory.getLogger(LanguageRESTService.class);\n+    \n+    /**\n+     * The path to the translation folder within the webapp.\n+     */\n+    private static final String TRANSLATION_PATHS = \"/translations\";\n+    \n+    /**\n+     * The JSON property for the human readable display name.\n+     */\n+    private static final String LANGUAGE_DISPLAY_NAME_KEY = \"NAME\";\n+    \n+    /**\n+     * The Jackson parser for parsing the language JSON files.\n+     */\n+    private static final ObjectMapper mapper = new ObjectMapper();\n+    \n+    /**\n+     * The regular expression to use for parsing the language key from the\n+     * filename.\n+     */\n+    private static final Pattern LANGUAGE_KEY_PATTERN = Pattern.compile(\".*/([a-z]+_[A-Z]+)\\\\.json\");\n+    \n+    /**\n+     * Returns a map of all available language keys to their corresponding\n+     * human-readable names.\n+     * \n+     * @param authToken\n+     *     The authentication token that is used to authenticate the user\n+     *     performing the operation.\n+     *\n+     * @param servletContext\n+     *     The ServletContext associated with the request.\n+     *\n+     * @return\n+     *     A list of languages defined in the system, consisting of \n+     *     language display name and key.\n+     *\n+     * @throws GuacamoleException\n+     *     If an error occurs while retrieving the available languages.\n+     */\n+    @GET\n+    @AuthProviderRESTExposure\n+    public Map<String, String> getLanguages(@QueryParam(\"token\") String authToken,\n+            @Context ServletContext servletContext) throws GuacamoleException {\n+        \n+        // Get the paths of all the translation files\n+        Set<String> resourcePaths = servletContext.getResourcePaths(TRANSLATION_PATHS);\n+        \n+        // If no translation files found, return an empty map\n+        if (resourcePaths == null)\n+            return Collections.EMPTY_MAP;\n+        \n+        Map<String, String> languageMap = new HashMap<String, String>();\n+        \n+        // Iterate through all the found language files and add them to the return map\n+        for(String resourcePath : resourcePaths) {","path":"guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/language/LanguageRESTService.java","position":116,"original_position":116,"commit_id":"c2b23027080e7b200358134e070b0c8bc0231cd9","original_commit_id":"c2b23027080e7b200358134e070b0c8bc0231cd9","user":{"login":"mike-jumper","id":4632905,"avatar_url":"https://avatars.githubusercontent.com/u/4632905?v=3","gravatar_id":"","url":"https://api.github.com/users/mike-jumper","html_url":"https://github.com/mike-jumper","followers_url":"https://api.github.com/users/mike-jumper/followers","following_url":"https://api.github.com/users/mike-jumper/following{/other_user}","gists_url":"https://api.github.com/users/mike-jumper/gists{/gist_id}","starred_url":"https://api.github.com/users/mike-jumper/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mike-jumper/subscriptions","organizations_url":"https://api.github.com/users/mike-jumper/orgs","repos_url":"https://api.github.com/users/mike-jumper/repos","events_url":"https://api.github.com/users/mike-jumper/events{/privacy}","received_events_url":"https://api.github.com/users/mike-jumper/received_events","type":"User","site_admin":false},"body":"Space after the ```for``` please.","created_at":"2015-04-23T05:45:30Z","updated_at":"2015-04-23T05:45:30Z","html_url":"https://github.com/glyptodon/guacamole-client/pull/155#discussion_r28937717","pull_request_url":"https://api.github.com/repos/glyptodon/guacamole-client/pulls/155","_links":{"self":{"href":"https://api.github.com/repos/glyptodon/guacamole-client/pulls/comments/28937717"},"html":{"href":"https://github.com/glyptodon/guacamole-client/pull/155#discussion_r28937717"},"pull_request":{"href":"https://api.github.com/repos/glyptodon/guacamole-client/pulls/155"}}},"pull_request":{"url":"https://api.github.com/repos/glyptodon/guacamole-client/pulls/155","id":33925621,"html_url":"https://github.com/glyptodon/guacamole-client/pull/155","diff_url":"https://github.com/glyptodon/guacamole-client/pull/155.diff","patch_url":"https://github.com/glyptodon/guacamole-client/pull/155.patch","issue_url":"https://api.github.com/repos/glyptodon/guacamole-client/issues/155","number":155,"state":"open","locked":false,"title":"GUAC-1053 Allow selection of display language","user":{"login":"jmuehlner","id":4633119,"avatar_url":"https://avatars.githubusercontent.com/u/4633119?v=3","gravatar_id":"","url":"https://api.github.com/users/jmuehlner","html_url":"https://github.com/jmuehlner","followers_url":"https://api.github.com/users/jmuehlner/followers","following_url":"https://api.github.com/users/jmuehlner/following{/other_user}","gists_url":"https://api.github.com/users/jmuehlner/gists{/gist_id}","starred_url":"https://api.github.com/users/jmuehlner/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jmuehlner/subscriptions","organizations_url":"https://api.github.com/users/jmuehlner/orgs","repos_url":"https://api.github.com/users/jmuehlner/repos","events_url":"https://api.github.com/users/jmuehlner/events{/privacy}","received_events_url":"https://api.github.com/users/jmuehlner/received_events","type":"User","site_admin":false},"body":"","created_at":"2015-04-23T05:40:48Z","updated_at":"2015-04-23T05:45:30Z","closed_at":null,"merged_at":null,"merge_commit_sha":"4e4b399754f23956262c41e9103e123922eac1a9","assignee":{"login":"mike-jumper","id":4632905,"avatar_url":"https://avatars.githubusercontent.com/u/4632905?v=3","gravatar_id":"","url":"https://api.github.com/users/mike-jumper","html_url":"https://github.com/mike-jumper","followers_url":"https://api.github.com/users/mike-jumper/followers","following_url":"https://api.github.com/users/mike-jumper/following{/other_user}","gists_url":"https://api.github.com/users/mike-jumper/gists{/gist_id}","starred_url":"https://api.github.com/users/mike-jumper/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mike-jumper/subscriptions","organizations_url":"https://api.github.com/users/mike-jumper/orgs","repos_url":"https://api.github.com/users/mike-jumper/repos","events_url":"https://api.github.com/users/mike-jumper/events{/privacy}","received_events_url":"https://api.github.com/users/mike-jumper/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/glyptodon/guacamole-client/pulls/155/commits","review_comments_url":"https://api.github.com/repos/glyptodon/guacamole-client/pulls/155/comments","review_comment_url":"https://api.github.com/repos/glyptodon/guacamole-client/pulls/comments{/number}","comments_url":"https://api.github.com/repos/glyptodon/guacamole-client/issues/155/comments","statuses_url":"https://api.github.com/repos/glyptodon/guacamole-client/statuses/c2b23027080e7b200358134e070b0c8bc0231cd9","head":{"label":"glyptodon:GUAC-1053","ref":"GUAC-1053","sha":"c2b23027080e7b200358134e070b0c8bc0231cd9","user":{"login":"glyptodon","id":4632960,"avatar_url":"https://avatars.githubusercontent.com/u/4632960?v=3","gravatar_id":"","url":"https://api.github.com/users/glyptodon","html_url":"https://github.com/glyptodon","followers_url":"https://api.github.com/users/glyptodon/followers","following_url":"https://api.github.com/users/glyptodon/following{/other_user}","gists_url":"https://api.github.com/users/glyptodon/gists{/gist_id}","starred_url":"https://api.github.com/users/glyptodon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/glyptodon/subscriptions","organizations_url":"https://api.github.com/users/glyptodon/orgs","repos_url":"https://api.github.com/users/glyptodon/repos","events_url":"https://api.github.com/users/glyptodon/events{/privacy}","received_events_url":"https://api.github.com/users/glyptodon/received_events","type":"Organization","site_admin":false},"repo":{"id":10532531,"name":"guacamole-client","full_name":"glyptodon/guacamole-client","owner":{"login":"glyptodon","id":4632960,"avatar_url":"https://avatars.githubusercontent.com/u/4632960?v=3","gravatar_id":"","url":"https://api.github.com/users/glyptodon","html_url":"https://github.com/glyptodon","followers_url":"https://api.github.com/users/glyptodon/followers","following_url":"https://api.github.com/users/glyptodon/following{/other_user}","gists_url":"https://api.github.com/users/glyptodon/gists{/gist_id}","starred_url":"https://api.github.com/users/glyptodon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/glyptodon/subscriptions","organizations_url":"https://api.github.com/users/glyptodon/orgs","repos_url":"https://api.github.com/users/glyptodon/repos","events_url":"https://api.github.com/users/glyptodon/events{/privacy}","received_events_url":"https://api.github.com/users/glyptodon/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/glyptodon/guacamole-client","description":"The HTML5/JavaScript Guacamole client, its containing web application, and related components.","fork":false,"url":"https://api.github.com/repos/glyptodon/guacamole-client","forks_url":"https://api.github.com/repos/glyptodon/guacamole-client/forks","keys_url":"https://api.github.com/repos/glyptodon/guacamole-client/keys{/key_id}","collaborators_url":"https://api.github.com/repos/glyptodon/guacamole-client/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/glyptodon/guacamole-client/teams","hooks_url":"https://api.github.com/repos/glyptodon/guacamole-client/hooks","issue_events_url":"https://api.github.com/repos/glyptodon/guacamole-client/issues/events{/number}","events_url":"https://api.github.com/repos/glyptodon/guacamole-client/events","assignees_url":"https://api.github.com/repos/glyptodon/guacamole-client/assignees{/user}","branches_url":"https://api.github.com/repos/glyptodon/guacamole-client/branches{/branch}","tags_url":"https://api.github.com/repos/glyptodon/guacamole-client/tags","blobs_url":"https://api.github.com/repos/glyptodon/guacamole-client/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/glyptodon/guacamole-client/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/glyptodon/guacamole-client/git/refs{/sha}","trees_url":"https://api.github.com/repos/glyptodon/guacamole-client/git/trees{/sha}","statuses_url":"https://api.github.com/repos/glyptodon/guacamole-client/statuses/{sha}","languages_url":"https://api.github.com/repos/glyptodon/guacamole-client/languages","stargazers_url":"https://api.github.com/repos/glyptodon/guacamole-client/stargazers","contributors_url":"https://api.github.com/repos/glyptodon/guacamole-client/contributors","subscribers_url":"https://api.github.com/repos/glyptodon/guacamole-client/subscribers","subscription_url":"https://api.github.com/repos/glyptodon/guacamole-client/subscription","commits_url":"https://api.github.com/repos/glyptodon/guacamole-client/commits{/sha}","git_commits_url":"https://api.github.com/repos/glyptodon/guacamole-client/git/commits{/sha}","comments_url":"https://api.github.com/repos/glyptodon/guacamole-client/comments{/number}","issue_comment_url":"https://api.github.com/repos/glyptodon/guacamole-client/issues/comments{/number}","contents_url":"https://api.github.com/repos/glyptodon/guacamole-client/contents/{+path}","compare_url":"https://api.github.com/repos/glyptodon/guacamole-client/compare/{base}...{head}","merges_url":"https://api.github.com/repos/glyptodon/guacamole-client/merges","archive_url":"https://api.github.com/repos/glyptodon/guacamole-client/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/glyptodon/guacamole-client/downloads","issues_url":"https://api.github.com/repos/glyptodon/guacamole-client/issues{/number}","pulls_url":"https://api.github.com/repos/glyptodon/guacamole-client/pulls{/number}","milestones_url":"https://api.github.com/repos/glyptodon/guacamole-client/milestones{/number}","notifications_url":"https://api.github.com/repos/glyptodon/guacamole-client/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/glyptodon/guacamole-client/labels{/name}","releases_url":"https://api.github.com/repos/glyptodon/guacamole-client/releases{/id}","created_at":"2013-06-06T17:45:24Z","updated_at":"2015-04-22T23:03:21Z","pushed_at":"2015-04-23T05:40:48Z","git_url":"git://github.com/glyptodon/guacamole-client.git","ssh_url":"git@github.com:glyptodon/guacamole-client.git","clone_url":"https://github.com/glyptodon/guacamole-client.git","svn_url":"https://github.com/glyptodon/guacamole-client","homepage":"http://guac-dev.org/","size":14360,"stargazers_count":522,"watchers_count":522,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":111,"mirror_url":null,"open_issues_count":5,"forks":111,"open_issues":5,"watchers":522,"default_branch":"master"}},"base":{"label":"glyptodon:master","ref":"master","sha":"3ea93c30b07782fbb790413822c386cbeb28a578","user":{"login":"glyptodon","id":4632960,"avatar_url":"https://avatars.githubusercontent.com/u/4632960?v=3","gravatar_id":"","url":"https://api.github.com/users/glyptodon","html_url":"https://github.com/glyptodon","followers_url":"https://api.github.com/users/glyptodon/followers","following_url":"https://api.github.com/users/glyptodon/following{/other_user}","gists_url":"https://api.github.com/users/glyptodon/gists{/gist_id}","starred_url":"https://api.github.com/users/glyptodon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/glyptodon/subscriptions","organizations_url":"https://api.github.com/users/glyptodon/orgs","repos_url":"https://api.github.com/users/glyptodon/repos","events_url":"https://api.github.com/users/glyptodon/events{/privacy}","received_events_url":"https://api.github.com/users/glyptodon/received_events","type":"Organization","site_admin":false},"repo":{"id":10532531,"name":"guacamole-client","full_name":"glyptodon/guacamole-client","owner":{"login":"glyptodon","id":4632960,"avatar_url":"https://avatars.githubusercontent.com/u/4632960?v=3","gravatar_id":"","url":"https://api.github.com/users/glyptodon","html_url":"https://github.com/glyptodon","followers_url":"https://api.github.com/users/glyptodon/followers","following_url":"https://api.github.com/users/glyptodon/following{/other_user}","gists_url":"https://api.github.com/users/glyptodon/gists{/gist_id}","starred_url":"https://api.github.com/users/glyptodon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/glyptodon/subscriptions","organizations_url":"https://api.github.com/users/glyptodon/orgs","repos_url":"https://api.github.com/users/glyptodon/repos","events_url":"https://api.github.com/users/glyptodon/events{/privacy}","received_events_url":"https://api.github.com/users/glyptodon/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/glyptodon/guacamole-client","description":"The HTML5/JavaScript Guacamole client, its containing web application, and related components.","fork":false,"url":"https://api.github.com/repos/glyptodon/guacamole-client","forks_url":"https://api.github.com/repos/glyptodon/guacamole-client/forks","keys_url":"https://api.github.com/repos/glyptodon/guacamole-client/keys{/key_id}","collaborators_url":"https://api.github.com/repos/glyptodon/guacamole-client/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/glyptodon/guacamole-client/teams","hooks_url":"https://api.github.com/repos/glyptodon/guacamole-client/hooks","issue_events_url":"https://api.github.com/repos/glyptodon/guacamole-client/issues/events{/number}","events_url":"https://api.github.com/repos/glyptodon/guacamole-client/events","assignees_url":"https://api.github.com/repos/glyptodon/guacamole-client/assignees{/user}","branches_url":"https://api.github.com/repos/glyptodon/guacamole-client/branches{/branch}","tags_url":"https://api.github.com/repos/glyptodon/guacamole-client/tags","blobs_url":"https://api.github.com/repos/glyptodon/guacamole-client/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/glyptodon/guacamole-client/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/glyptodon/guacamole-client/git/refs{/sha}","trees_url":"https://api.github.com/repos/glyptodon/guacamole-client/git/trees{/sha}","statuses_url":"https://api.github.com/repos/glyptodon/guacamole-client/statuses/{sha}","languages_url":"https://api.github.com/repos/glyptodon/guacamole-client/languages","stargazers_url":"https://api.github.com/repos/glyptodon/guacamole-client/stargazers","contributors_url":"https://api.github.com/repos/glyptodon/guacamole-client/contributors","subscribers_url":"https://api.github.com/repos/glyptodon/guacamole-client/subscribers","subscription_url":"https://api.github.com/repos/glyptodon/guacamole-client/subscription","commits_url":"https://api.github.com/repos/glyptodon/guacamole-client/commits{/sha}","git_commits_url":"https://api.github.com/repos/glyptodon/guacamole-client/git/commits{/sha}","comments_url":"https://api.github.com/repos/glyptodon/guacamole-client/comments{/number}","issue_comment_url":"https://api.github.com/repos/glyptodon/guacamole-client/issues/comments{/number}","contents_url":"https://api.github.com/repos/glyptodon/guacamole-client/contents/{+path}","compare_url":"https://api.github.com/repos/glyptodon/guacamole-client/compare/{base}...{head}","merges_url":"https://api.github.com/repos/glyptodon/guacamole-client/merges","archive_url":"https://api.github.com/repos/glyptodon/guacamole-client/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/glyptodon/guacamole-client/downloads","issues_url":"https://api.github.com/repos/glyptodon/guacamole-client/issues{/number}","pulls_url":"https://api.github.com/repos/glyptodon/guacamole-client/pulls{/number}","milestones_url":"https://api.github.com/repos/glyptodon/guacamole-client/milestones{/number}","notifications_url":"https://api.github.com/repos/glyptodon/guacamole-client/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/glyptodon/guacamole-client/labels{/name}","releases_url":"https://api.github.com/repos/glyptodon/guacamole-client/releases{/id}","created_at":"2013-06-06T17:45:24Z","updated_at":"2015-04-22T23:03:21Z","pushed_at":"2015-04-23T05:40:48Z","git_url":"git://github.com/glyptodon/guacamole-client.git","ssh_url":"git@github.com:glyptodon/guacamole-client.git","clone_url":"https://github.com/glyptodon/guacamole-client.git","svn_url":"https://github.com/glyptodon/guacamole-client","homepage":"http://guac-dev.org/","size":14360,"stargazers_count":522,"watchers_count":522,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":111,"mirror_url":null,"open_issues_count":5,"forks":111,"open_issues":5,"watchers":522,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/glyptodon/guacamole-client/pulls/155"},"html":{"href":"https://github.com/glyptodon/guacamole-client/pull/155"},"issue":{"href":"https://api.github.com/repos/glyptodon/guacamole-client/issues/155"},"comments":{"href":"https://api.github.com/repos/glyptodon/guacamole-client/issues/155/comments"},"review_comments":{"href":"https://api.github.com/repos/glyptodon/guacamole-client/pulls/155/comments"},"review_comment":{"href":"https://api.github.com/repos/glyptodon/guacamole-client/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/glyptodon/guacamole-client/pulls/155/commits"},"statuses":{"href":"https://api.github.com/repos/glyptodon/guacamole-client/statuses/c2b23027080e7b200358134e070b0c8bc0231cd9"}}}}