GitHub PullRequestReviewCommentEvent at 2014-07-08 17:02:39
Repository: CiteSeerX
Actor: fanchyna
Payload: {"action":"created","comment":{"url":"https://api.github.com/repos/SeerLabs/CiteSeerX/pulls/comments/14665492","id":14665492,"diff_hunk":"@@ -0,0 +1,271 @@\n+/*\n+ * Copyright 2007 Penn State University\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *     http://www.apache.org/licenses/LICENSE-2.0\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+package edu.psu.citeseerx.webutils;\n+\n+import java.io.*;\n+import java.util.Date;\n+import java.util.HashMap;\n+import javax.servlet.*;\n+import javax.servlet.http.*;\n+\n+/**\n+ * Filter to prevent massive downloads from the same ip address. \n+ * @author Isaac Councill\n+ * @author Jian Wu\n+ * @version $Rev$ $Date$\n+ */\n+public class SimpleQueryLimitFilter implements Filter {\n+    \n+    // the default max number of queries daily\n+    private int limit = 3;\n+    private String redirectUrl = \"\";\n+\n+    // 3 Seconds.\n+    private Long timeLimit = new Long(3000);\n+    \n+    // \"ipQueryLog.txt\" contains queries that exceed the limit. These requests\n+    // are not full-filled\n+    private HashMap<String,Integer> dlCounts = new HashMap<String,Integer>();\n+    private String[] allowedUserAgents = new String[0];\n+    private String[] allowedIPs = new String[0];\n+    private String ipLogFilter = \"ipQueryLog.txt\";\n+    private BufferedWriter ipLogWriter = null;\n+    \n+    private HashMap<String, Long>sameDL = new HashMap<String, Long>();\n+ \n+    /* Read parameters from Servlet configeration file\n+     * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)\n+     */\n+    public void init(FilterConfig config) throws ServletException {\n+        \n+        // the Url when the limit is exceeded\n+        String redirectUrlStr = config.getInitParameter(\"redirectUrl\");\n+        if (redirectUrlStr != null) {\n+            redirectUrl = redirectUrlStr;\n+        } else {\n+            System.err.println(\"SimpleQueryLimitFilter: no redirectUrl \" +\n+                    \"specified!\");\n+        }\n+        \n+        // the max number of Queries daily configured in web.xml\n+        String limitStr = config.getInitParameter(\"limit\");\n+        try {\n+            limit = Integer.parseInt(limitStr);\n+        } catch (Exception e) {\n+            e.printStackTrace();\n+            System.err.println(\"SimpleQueryLimitFilter: +\" +\n+                    \"Invalid limit specified: \"+limitStr);\n+            System.err.println(\"Using default limit of \"+limit);\n+        }\n+ \n+        // the allowed agents that are not limited (optional)\n+        String allowedua = config.getInitParameter(\"allowedUserAgents\");\n+        if (allowedua != null) {\n+            allowedUserAgents = allowedua.split(\",\");\n+            for (int i=0; i<allowedUserAgents.length; i++) {\n+                String str = allowedUserAgents[i];\n+                str = str.trim();\n+                str = str.toLowerCase();\n+                allowedUserAgents[i] = str;\n+            }\n+        }\n+\n+        // the allowed IPs that are not limited (optional)\n+        String allowedip = config.getInitParameter(\"allowedIPs\");\n+        if(allowedip != null) {\n+            allowedIPs = allowedip.split(\",\");\n+            for(int i=0; i < allowedIPs.length; i++) {\n+                String str = allowedIPs[i];\n+                str = str.trim();\n+                allowedIPs[i] = str;\n+            }\t    \n+        }\n+\n+        // time between consecutive hits from the same IP\n+        String timeLimitStr = config.getInitParameter(\"timeLimit\");\n+        try {\n+            timeLimit = Long.parseLong(timeLimitStr);\n+        }catch (Exception e) {\n+            e.printStackTrace();\n+            System.err.println(\"SimpleQueryLimitFilter: \" +\n+                    \"Invalid time limit specified: \"+timeLimitStr);\n+            System.err.println(\"Using default limit of \"+timeLimit);\n+        }\n+\n+        // log file recording query requests\n+        String ipLogFileStr = config.getInitParameter(\"ipLogFile\");\n+        if (ipLogFileStr != null) {\n+            ipLogFilter = ipLogFileStr;\n+        }\n+        try {\n+            ipLogFilter = config.getServletContext().getRealPath(\"/\") +\n+                ipLogFilter;\n+            ipLogWriter = new BufferedWriter(new OutputStreamWriter(\n+                    new FileOutputStream(ipLogFilter, true), \"UTF-8\"));\n+        }catch (Exception e) {\n+            ipLogWriter = null;\n+            e.printStackTrace();\n+            System.err.println(\"SimpleQueryLimitFilter: \" +\n+                    \"A problem ocurred while opening the log file: \"+ipLogFilter);\n+        }\n+    }  //- init\n+    \n+    \n+    /* (non-Javadoc)\n+     * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)\n+     */\n+    public void doFilter(ServletRequest request,\n+            ServletResponse response, FilterChain chain)\n+    throws IOException, ServletException {\n+\n+        // if request is from an allowed agent or IP, skip this filter and \n+        // go to the next filter\n+        if (allowedUserAgentorIP(request)) {\n+            chain.doFilter(request, response);\n+            return;\n+        }\n+        \n+        // Actions taken if request limit is exceeded\n+        // (1) set status to 403; \n+        // (2) redirect to error page;\n+        if (requestsExceeded(request)) {\n+            if (response instanceof HttpServletResponse) {\n+                HttpServletResponse hreq = (HttpServletResponse)response;\n+                hreq.setStatus(403);\n+                String context = ((HttpServletRequest)request).getContextPath();\n+                hreq.sendRedirect(context+redirectUrl);\n+            }\n+            return;\n+        }\n+\n+        // go to the next filter\n+        chain.doFilter(request, response);\n+        \n+    }  //- doFilter\n+    \n+    \n+    /*\n+     * Judge if the query limit is exceeded\n+     */\n+    private synchronized boolean requestsExceeded(ServletRequest request) {\n+\n+        updateFlushTime();\n+        String ipaddr = request.getRemoteAddr();\n+        HttpServletRequest hreq = (HttpServletRequest)request;\n+        String rQS = hreq.getQueryString();","path":"src/java/edu/psu/citeseerx/webutils/SimpleQueryLimitFilter.java","position":165,"original_position":165,"commit_id":"a51b93d673cc10deeb46db528436f06b85a1d9a4","original_commit_id":"a51b93d673cc10deeb46db528436f06b85a1d9a4","user":{"login":"fanchyna","id":1759659,"avatar_url":"https://avatars.githubusercontent.com/u/1759659?","gravatar_id":"87a5834b3cd7dd97132a63b50df34edd","url":"https://api.github.com/users/fanchyna","html_url":"https://github.com/fanchyna","followers_url":"https://api.github.com/users/fanchyna/followers","following_url":"https://api.github.com/users/fanchyna/following{/other_user}","gists_url":"https://api.github.com/users/fanchyna/gists{/gist_id}","starred_url":"https://api.github.com/users/fanchyna/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fanchyna/subscriptions","organizations_url":"https://api.github.com/users/fanchyna/orgs","repos_url":"https://api.github.com/users/fanchyna/repos","events_url":"https://api.github.com/users/fanchyna/events{/privacy}","received_events_url":"https://api.github.com/users/fanchyna/received_events","type":"User","site_admin":false},"body":"Yes. This was inherited from the SimpleDownloadLimitFilter.java by Isaac. This only prevents people from repetitively searching with the same keywords. It allows people to search with different keywords even if delta(t)<T(limit). Note that there are two hash tables: sameQL is used to prevent people from searching using the same keywords too quickly; qlCounts is used to prevent people from searching too many times from the same IP. ","created_at":"2014-07-08T17:02:39Z","updated_at":"2014-07-08T17:02:39Z","html_url":"https://github.com/SeerLabs/CiteSeerX/pull/13#discussion_r14665492","pull_request_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/pulls/13","_links":{"self":{"href":"https://api.github.com/repos/SeerLabs/CiteSeerX/pulls/comments/14665492"},"html":{"href":"https://github.com/SeerLabs/CiteSeerX/pull/13#discussion_r14665492"},"pull_request":{"href":"https://api.github.com/repos/SeerLabs/CiteSeerX/pulls/13"}}},"pull_request":{"url":"https://api.github.com/repos/SeerLabs/CiteSeerX/pulls/13","id":18057316,"html_url":"https://github.com/SeerLabs/CiteSeerX/pull/13","diff_url":"https://github.com/SeerLabs/CiteSeerX/pull/13.diff","patch_url":"https://github.com/SeerLabs/CiteSeerX/pull/13.patch","issue_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/issues/13","number":13,"state":"open","title":"limit queries","user":{"login":"fanchyna","id":1759659,"avatar_url":"https://avatars.githubusercontent.com/u/1759659?","gravatar_id":"87a5834b3cd7dd97132a63b50df34edd","url":"https://api.github.com/users/fanchyna","html_url":"https://github.com/fanchyna","followers_url":"https://api.github.com/users/fanchyna/followers","following_url":"https://api.github.com/users/fanchyna/following{/other_user}","gists_url":"https://api.github.com/users/fanchyna/gists{/gist_id}","starred_url":"https://api.github.com/users/fanchyna/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fanchyna/subscriptions","organizations_url":"https://api.github.com/users/fanchyna/orgs","repos_url":"https://api.github.com/users/fanchyna/repos","events_url":"https://api.github.com/users/fanchyna/events{/privacy}","received_events_url":"https://api.github.com/users/fanchyna/received_events","type":"User","site_admin":false},"body":"limit the number of queries per ip per day, default is 3, configurable in web.xml, effective immediately (no need to restart tomcat).\r\nfiles added: \r\n* queryexceeded.html\r\n* SimpleQueryLimitFilter.java\r\nfiles updated:\r\n* web.xml\r\n\r\n","created_at":"2014-07-07T17:27:24Z","updated_at":"2014-07-08T17:02:39Z","closed_at":null,"merged_at":null,"merge_commit_sha":"5b247dc440e4155a660d224728d69608ec958b51","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/pulls/13/commits","review_comments_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/pulls/13/comments","review_comment_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/pulls/comments/{number}","comments_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/issues/13/comments","statuses_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/statuses/a51b93d673cc10deeb46db528436f06b85a1d9a4","head":{"label":"SeerLabs:limit_request","ref":"limit_request","sha":"a51b93d673cc10deeb46db528436f06b85a1d9a4","user":{"login":"SeerLabs","id":4325086,"avatar_url":"https://avatars.githubusercontent.com/u/4325086?","gravatar_id":null,"url":"https://api.github.com/users/SeerLabs","html_url":"https://github.com/SeerLabs","followers_url":"https://api.github.com/users/SeerLabs/followers","following_url":"https://api.github.com/users/SeerLabs/following{/other_user}","gists_url":"https://api.github.com/users/SeerLabs/gists{/gist_id}","starred_url":"https://api.github.com/users/SeerLabs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SeerLabs/subscriptions","organizations_url":"https://api.github.com/users/SeerLabs/orgs","repos_url":"https://api.github.com/users/SeerLabs/repos","events_url":"https://api.github.com/users/SeerLabs/events{/privacy}","received_events_url":"https://api.github.com/users/SeerLabs/received_events","type":"Organization","site_admin":false},"repo":{"id":11351492,"name":"CiteSeerX","full_name":"SeerLabs/CiteSeerX","owner":{"login":"SeerLabs","id":4325086,"avatar_url":"https://avatars.githubusercontent.com/u/4325086?","gravatar_id":null,"url":"https://api.github.com/users/SeerLabs","html_url":"https://github.com/SeerLabs","followers_url":"https://api.github.com/users/SeerLabs/followers","following_url":"https://api.github.com/users/SeerLabs/following{/other_user}","gists_url":"https://api.github.com/users/SeerLabs/gists{/gist_id}","starred_url":"https://api.github.com/users/SeerLabs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SeerLabs/subscriptions","organizations_url":"https://api.github.com/users/SeerLabs/orgs","repos_url":"https://api.github.com/users/SeerLabs/repos","events_url":"https://api.github.com/users/SeerLabs/events{/privacy}","received_events_url":"https://api.github.com/users/SeerLabs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/SeerLabs/CiteSeerX","description":"CiteSeerX public repository","fork":false,"url":"https://api.github.com/repos/SeerLabs/CiteSeerX","forks_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/forks","keys_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/keys{/key_id}","collaborators_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/teams","hooks_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/hooks","issue_events_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/issues/events{/number}","events_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/events","assignees_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/assignees{/user}","branches_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/branches{/branch}","tags_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/tags","blobs_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/git/refs{/sha}","trees_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/git/trees{/sha}","statuses_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/statuses/{sha}","languages_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/languages","stargazers_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/stargazers","contributors_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/contributors","subscribers_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/subscribers","subscription_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/subscription","commits_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/commits{/sha}","git_commits_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/git/commits{/sha}","comments_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/comments{/number}","issue_comment_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/issues/comments/{number}","contents_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/contents/{+path}","compare_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/compare/{base}...{head}","merges_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/merges","archive_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/downloads","issues_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/issues{/number}","pulls_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/pulls{/number}","milestones_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/milestones{/number}","notifications_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/labels{/name}","releases_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/releases{/id}","created_at":"2013-07-11T19:51:28Z","updated_at":"2014-06-01T20:14:02Z","pushed_at":"2014-07-07T17:39:58Z","git_url":"git://github.com/SeerLabs/CiteSeerX.git","ssh_url":"git@github.com:SeerLabs/CiteSeerX.git","clone_url":"https://github.com/SeerLabs/CiteSeerX.git","svn_url":"https://github.com/SeerLabs/CiteSeerX","homepage":null,"size":71769,"stargazers_count":10,"watchers_count":10,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"forks_count":10,"mirror_url":null,"open_issues_count":4,"forks":10,"open_issues":4,"watchers":10,"default_branch":"master"}},"base":{"label":"SeerLabs:master","ref":"master","sha":"c5f8f214a07636052a690bbba05776383ab7e2da","user":{"login":"SeerLabs","id":4325086,"avatar_url":"https://avatars.githubusercontent.com/u/4325086?","gravatar_id":null,"url":"https://api.github.com/users/SeerLabs","html_url":"https://github.com/SeerLabs","followers_url":"https://api.github.com/users/SeerLabs/followers","following_url":"https://api.github.com/users/SeerLabs/following{/other_user}","gists_url":"https://api.github.com/users/SeerLabs/gists{/gist_id}","starred_url":"https://api.github.com/users/SeerLabs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SeerLabs/subscriptions","organizations_url":"https://api.github.com/users/SeerLabs/orgs","repos_url":"https://api.github.com/users/SeerLabs/repos","events_url":"https://api.github.com/users/SeerLabs/events{/privacy}","received_events_url":"https://api.github.com/users/SeerLabs/received_events","type":"Organization","site_admin":false},"repo":{"id":11351492,"name":"CiteSeerX","full_name":"SeerLabs/CiteSeerX","owner":{"login":"SeerLabs","id":4325086,"avatar_url":"https://avatars.githubusercontent.com/u/4325086?","gravatar_id":null,"url":"https://api.github.com/users/SeerLabs","html_url":"https://github.com/SeerLabs","followers_url":"https://api.github.com/users/SeerLabs/followers","following_url":"https://api.github.com/users/SeerLabs/following{/other_user}","gists_url":"https://api.github.com/users/SeerLabs/gists{/gist_id}","starred_url":"https://api.github.com/users/SeerLabs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SeerLabs/subscriptions","organizations_url":"https://api.github.com/users/SeerLabs/orgs","repos_url":"https://api.github.com/users/SeerLabs/repos","events_url":"https://api.github.com/users/SeerLabs/events{/privacy}","received_events_url":"https://api.github.com/users/SeerLabs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/SeerLabs/CiteSeerX","description":"CiteSeerX public repository","fork":false,"url":"https://api.github.com/repos/SeerLabs/CiteSeerX","forks_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/forks","keys_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/keys{/key_id}","collaborators_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/teams","hooks_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/hooks","issue_events_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/issues/events{/number}","events_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/events","assignees_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/assignees{/user}","branches_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/branches{/branch}","tags_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/tags","blobs_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/git/refs{/sha}","trees_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/git/trees{/sha}","statuses_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/statuses/{sha}","languages_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/languages","stargazers_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/stargazers","contributors_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/contributors","subscribers_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/subscribers","subscription_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/subscription","commits_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/commits{/sha}","git_commits_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/git/commits{/sha}","comments_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/comments{/number}","issue_comment_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/issues/comments/{number}","contents_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/contents/{+path}","compare_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/compare/{base}...{head}","merges_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/merges","archive_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/downloads","issues_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/issues{/number}","pulls_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/pulls{/number}","milestones_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/milestones{/number}","notifications_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/labels{/name}","releases_url":"https://api.github.com/repos/SeerLabs/CiteSeerX/releases{/id}","created_at":"2013-07-11T19:51:28Z","updated_at":"2014-06-01T20:14:02Z","pushed_at":"2014-07-07T17:39:58Z","git_url":"git://github.com/SeerLabs/CiteSeerX.git","ssh_url":"git@github.com:SeerLabs/CiteSeerX.git","clone_url":"https://github.com/SeerLabs/CiteSeerX.git","svn_url":"https://github.com/SeerLabs/CiteSeerX","homepage":null,"size":71769,"stargazers_count":10,"watchers_count":10,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"forks_count":10,"mirror_url":null,"open_issues_count":4,"forks":10,"open_issues":4,"watchers":10,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/SeerLabs/CiteSeerX/pulls/13"},"html":{"href":"https://github.com/SeerLabs/CiteSeerX/pull/13"},"issue":{"href":"https://api.github.com/repos/SeerLabs/CiteSeerX/issues/13"},"comments":{"href":"https://api.github.com/repos/SeerLabs/CiteSeerX/issues/13/comments"},"review_comments":{"href":"https://api.github.com/repos/SeerLabs/CiteSeerX/pulls/13/comments"},"review_comment":{"href":"https://api.github.com/repos/SeerLabs/CiteSeerX/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/SeerLabs/CiteSeerX/pulls/13/commits"},"statuses":{"href":"https://api.github.com/repos/SeerLabs/CiteSeerX/statuses/a51b93d673cc10deeb46db528436f06b85a1d9a4"}}}}