{"action":"created","comment":{"url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/comments/29073605","id":29073605,"diff_hunk":"@@ -1,69 +1,197 @@\n (ns cider.nrepl.middleware.debug\n+  \"Expression-based debugger for clojure code\"\n+  {:author \"Artur Malabarba\"}\n   (:require [clojure.tools.nrepl.transport :as transport]\n             [clojure.tools.nrepl.middleware :refer [set-descriptor!]]\n             [clojure.tools.nrepl.misc :refer [response-for]]\n-            [cider.nrepl.middleware.util.instrument :refer [instrument]]\n-            [debugger.time :as t]\n-            [debugger.config :as c]\n-            [debugger.core :refer [break]]))\n+            [clojure.tools.nrepl.middleware.interruptible-eval :refer [*msg*]]\n+            [cider.nrepl.middleware.stacktrace :refer [analyze-causes]]\n+            [cider.nrepl.middleware.util.instrument :refer [instrument]]))\n \n-;;;; ## Interaction with the client\n+;;;; # The Debugger\n+;;; The debugger is divided into two parts, intrument.clj and\n+;;; debug.clj.\n+;;;\n+;;; - instrument.clj (which see), found in the util/ subdir, is\n+;;;   responsible for navigating a code data structure and\n+;;;   instrumenting all sexps of interest.\n+;;;\n+;;; - debug.clj is the debugger per se. It doesn't actually \"look\" at\n+;;;   the code it's being run on. It simply implements the breakpoint\n+;;;   logic as well as a number of functions to interact with the user\n+;;;   according to breakpoints placed by instrument.clj.\n+;;;\n+;;;   After the repl is started, before the debugger can be used, a\n+;;;   message must be sent by the client with the \"init-debugger\" op\n+;;;   (only one of these is necessary througout a session).\n+;;;   Afterwards, code can be instrumented by calling\n+;;;   `instrument-and-eval` on it (through the regular \"eval\" op).\n+;;;\n+;;;   Finally, when a breakpoint is reached due to running\n+;;;   instrumented code, an `need-debug-input` message is sent to the\n+;;;   client in response to the message used during initialization.\n+;;;   Execution of the code will halt until this message is replied.\n+;;;   It may specify a :prompt, it will specify an :input-type and a\n+;;;   :key, and it expects an :input key in the reply. The :key must\n+;;;   be contained in the reply, and :input-type may be:\n+;;;   - a vector of keywords, in which case one must be returned (but\n+;;;     note that the repl may convert these to non-keyword strings);\n+;;;   - the keyword :expression, in which case a single sexp must be\n+;;;     returned (as a string).\n+\n+;;;; ## Internal breakpoint logic\n+;;; Variables and functions used for navigating between breakpoints.\n+(def ^:dynamic *skip-breaks*\n+  \"Boolean or vector to determine whether to skip a breakpoint.\n+  Don't set or examine this directly, it is bound in the session\n+  binding map, use `skip-breaks!` and `skip-breaks?` instead.\n+  Its value is discarded at the end each eval session.\"\n+  nil)\n+\n+(defn- skip-breaks?\n+  \"True if the breakpoint at coordinates should be skipped.\n+  If *skip-breaks* is true, return true.\n+  If *skip-breaks* is a vector of integers, return true if coordinates\n+  are deeper than this vector.\"\n+  [coordinates]\n+  (when-let [sb (@(:session *msg*) #'*skip-breaks*)]\n+    (or\n+     ;; From :continue, skip everything.\n+     (true? sb)\n+     ;; From :out, skip some breaks.\n+     (let [parent (take (count sb) coordinates)]\n+       (and (= sb parent)\n+            (> (count coordinates) (count parent)))))))\n+\n+(defn- skip-breaks!\n+  \"Set the value of *skip-breaks* in the session binding map.\"\n+  [bool-or-vec]\n+  (swap! (:session *msg*) assoc #'*skip-breaks* bool-or-vec))\n+\n+(defn- abort!\n+  \"Stop current eval thread.\n+  This does not quit the repl, it only interrupts an eval operation.\"\n+  []\n+  (.stop (:thread (meta (:session *msg*)))))\n+\n+;;;; ## Getting user input\n ;;; `wrap-debug` receives an initial message from the client, stores\n-;;; it in `debugger-message`, and `breakpoint` answers it.\n-(def debugger-message (atom nil))\n+;;; it in `debugger-message`, and `breakpoint` answers it when asking\n+;;; for input.\n+(def debugger-message\n+  \"The message being used to communicate with the client.\n+  Stored by the \\\"init-debugger\\\" op, and used by `read-debug` to ask\n+  for debug input through the :need-debug-input status.\"\n+  (atom nil))\n \n-(defn wrap-debug [h]\n-  (fn [{:keys [op force] :as msg}]\n-    (if (= \"init-debugger\" op)\n-      (let [stored-message @debugger-message]\n-        (if (and stored-message (not force))\n-          (transport/send (:transport msg)\n-                          (response-for msg :status :done))\n-          (do (when stored-message\n-                (transport/send (:transport stored-message)\n-                                (response-for stored-message :status :done)))\n-              ;; TODO: Redefine this in the session binding map, see inspect.clj.\n-              (reset! debugger-message msg))))\n-      (h msg))))\n+(def debugger-input\n+  \"Map atom holding all unprocessed debug inputs.\n+  This is where the \\\"debug\\\" op stores replies received for debug\n+  input requests. `read-debug` will halt until it finds its input in\n+  this map (identified by a key), and will `dissoc` it afterwards.\"\n+  (atom nil))\n+\n+(defn- read-debug\n+  \"Like `read`, but reply is sent through `debugger-message`.\n+  type is sent in the message as :input-type.\"\n+  [extras type]\n+  (let [key (rand-int 10000000)]\n+    (->> (assoc extras\n+                :status :need-debug-input\n+                :key key\n+                :input-type type)\n+         (response-for @debugger-message)\n+         (transport/send (:transport @debugger-message)))\n+    (while (not (@debugger-input key))\n+      (java.lang.Thread/sleep 100))\n+    (let [input (@debugger-input key)]\n+      (swap! debugger-input dissoc key)\n+      input)))\n+\n+(def ^:dynamic *locals*\n+  \"Bound by the `breakpoint` macro to the local &env.\"\n+  {})\n \n-(defn breakpoint\n+(defn- eval-with-locals\n+  \"`eval` form wrapped in a let of the *locals* map.\"\n+  [form]\n+  (eval\n+   `(let ~(vec (mapcat #(list % `(*locals* '~%)) (keys *locals*)))\n+      ~form)))\n+\n+(defn- read-debug-eval-expression\n+  \"Read and eval an expression from the client.\n+  extras is a map to be added to the message, and prompt is added into\n+  the :prompt key.\"\n+  [prompt extras]\n+  (-> (assoc extras :prompt prompt)\n+      (read-debug :expression)\n+      eval-with-locals))\n+\n+(defn- read-debug-command\n+  \"Read and take action on a debugging command\"\n+  [value extras]\n+  (case (read-debug extras [:next :continue :out :inject :eval :quit])\n+    :next     value\n+    :continue (do (skip-breaks! true) value)\n+    :out      (do (skip-breaks! (butlast (:coor extras))) value)\n+    :inject   (read-debug-eval-expression \"Expression to inject: \" extras)\n+    :eval     (let [return (read-debug-eval-expression \"Expression to evaluate: \" extras)]\n+                (read-debug-command value (assoc extras :debug-value (pr-str return))))\n+    :quit     (abort!)))\n+\n+;;; ## High-level functions\n+(defmacro breakpoint\n   \"Send value and coordinates to the client through the debug channel.\n   Sends a response to the message stored in debugger-message.\"\n   [value extras]\n-  ;; If the user has recently replied (quit) to a `break` statement,\n-  ;; then debugger will not ask for input. Therefore, have to avoid\n-  ;; sending the following message in these cases.\n-  (if (->> (t/now) (t/interval @c/*last-quit-at*) t/in-seconds (< c/*skip-repl-if-last-quit-ago*))\n-    ;; TODO: If clj-debugger makes the `read` call in `read-fn`\n-    ;; configurable (perhaps with a dynamic variable) we would have to\n-    ;; divide our breakpoint into two messages.\n-    (do (transport/send\n-         (:transport @debugger-message)\n-         (response-for @debugger-message\n-                       (assoc extras\n-                              :debug-value (pr-str value)\n-                              :breakfunction nil)))\n-        ;; Send the actual break.\n-        (binding [*out* (new java.io.StringWriter)]\n-          (break value)))\n-    ;; Notify cider that a (break) is incoming, along with the value\n-    ;; of the instrumented sexp and instructions on how to find it in\n-    ;; the code.\n-    value))\n+  `(binding [*locals* ~(into {} (map (fn [[sym bind]] [`(quote ~sym) (.sym bind)]) &env))]","path":"src/cider/nrepl/middleware/debug.clj","position":189,"original_position":189,"commit_id":"6c40246cab89914e360180ced0608dc47c103b66","original_commit_id":"6c40246cab89914e360180ced0608dc47c103b66","user":{"login":"cichli","id":1759291,"avatar_url":"https://avatars.githubusercontent.com/u/1759291?v=3","gravatar_id":"","url":"https://api.github.com/users/cichli","html_url":"https://github.com/cichli","followers_url":"https://api.github.com/users/cichli/followers","following_url":"https://api.github.com/users/cichli/following{/other_user}","gists_url":"https://api.github.com/users/cichli/gists{/gist_id}","starred_url":"https://api.github.com/users/cichli/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cichli/subscriptions","organizations_url":"https://api.github.com/users/cichli/orgs","repos_url":"https://api.github.com/users/cichli/repos","events_url":"https://api.github.com/users/cichli/events{/privacy}","received_events_url":"https://api.github.com/users/cichli/received_events","type":"User","site_admin":false},"body":"Eastwood can't lint this, since it uses tools.analyzer, and `&env` is quite different in tools.analyzer. Check out [this commit](https://github.com/razum2um/clj-debugger/commit/377c34165e108035fcfb169fb17bafbb0aa0e34c) for a workaround.","created_at":"2015-04-24T18:31:49Z","updated_at":"2015-04-24T18:31:49Z","html_url":"https://github.com/clojure-emacs/cider-nrepl/pull/197#discussion_r29073605","pull_request_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/197","_links":{"self":{"href":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/comments/29073605"},"html":{"href":"https://github.com/clojure-emacs/cider-nrepl/pull/197#discussion_r29073605"},"pull_request":{"href":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/197"}}},"pull_request":{"url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/197","id":34066378,"html_url":"https://github.com/clojure-emacs/cider-nrepl/pull/197","diff_url":"https://github.com/clojure-emacs/cider-nrepl/pull/197.diff","patch_url":"https://github.com/clojure-emacs/cider-nrepl/pull/197.patch","issue_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/issues/197","number":197,"state":"open","locked":false,"title":"Debugger rewrite","user":{"login":"Malabarba","id":453029,"avatar_url":"https://avatars.githubusercontent.com/u/453029?v=3","gravatar_id":"","url":"https://api.github.com/users/Malabarba","html_url":"https://github.com/Malabarba","followers_url":"https://api.github.com/users/Malabarba/followers","following_url":"https://api.github.com/users/Malabarba/following{/other_user}","gists_url":"https://api.github.com/users/Malabarba/gists{/gist_id}","starred_url":"https://api.github.com/users/Malabarba/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Malabarba/subscriptions","organizations_url":"https://api.github.com/users/Malabarba/orgs","repos_url":"https://api.github.com/users/Malabarba/repos","events_url":"https://api.github.com/users/Malabarba/events{/privacy}","received_events_url":"https://api.github.com/users/Malabarba/received_events","type":"User","site_admin":false},"body":"- Rewrite the debugger to do most of the logic on the clojure side. Now, it only contacts cider.el when user input is needed.\r\n- New commands beyond the previous ones: `quit`, `out`, `eval`.\r\n- Much more documentation (which is why the line counts look so large).\r\n\r\nI'll push the cider.el side of this later today, but I wanted to get this PR open because the code is pretty independent of cider.el.\r\n\r\nHappy reading.\r\n","created_at":"2015-04-24T16:55:12Z","updated_at":"2015-04-24T18:31:49Z","closed_at":null,"merged_at":null,"merge_commit_sha":"6b5d598fa51de0419b6d6324f2503fb6ce4fd039","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/197/commits","review_comments_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/197/comments","review_comment_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/comments{/number}","comments_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/issues/197/comments","statuses_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/statuses/6c40246cab89914e360180ced0608dc47c103b66","head":{"label":"Malabarba:master","ref":"master","sha":"6c40246cab89914e360180ced0608dc47c103b66","user":{"login":"Malabarba","id":453029,"avatar_url":"https://avatars.githubusercontent.com/u/453029?v=3","gravatar_id":"","url":"https://api.github.com/users/Malabarba","html_url":"https://github.com/Malabarba","followers_url":"https://api.github.com/users/Malabarba/followers","following_url":"https://api.github.com/users/Malabarba/following{/other_user}","gists_url":"https://api.github.com/users/Malabarba/gists{/gist_id}","starred_url":"https://api.github.com/users/Malabarba/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Malabarba/subscriptions","organizations_url":"https://api.github.com/users/Malabarba/orgs","repos_url":"https://api.github.com/users/Malabarba/repos","events_url":"https://api.github.com/users/Malabarba/events{/privacy}","received_events_url":"https://api.github.com/users/Malabarba/received_events","type":"User","site_admin":false},"repo":{"id":32170454,"name":"cider-nrepl","full_name":"Malabarba/cider-nrepl","owner":{"login":"Malabarba","id":453029,"avatar_url":"https://avatars.githubusercontent.com/u/453029?v=3","gravatar_id":"","url":"https://api.github.com/users/Malabarba","html_url":"https://github.com/Malabarba","followers_url":"https://api.github.com/users/Malabarba/followers","following_url":"https://api.github.com/users/Malabarba/following{/other_user}","gists_url":"https://api.github.com/users/Malabarba/gists{/gist_id}","starred_url":"https://api.github.com/users/Malabarba/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Malabarba/subscriptions","organizations_url":"https://api.github.com/users/Malabarba/orgs","repos_url":"https://api.github.com/users/Malabarba/repos","events_url":"https://api.github.com/users/Malabarba/events{/privacy}","received_events_url":"https://api.github.com/users/Malabarba/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/Malabarba/cider-nrepl","description":"nREPL middleware for CIDER","fork":true,"url":"https://api.github.com/repos/Malabarba/cider-nrepl","forks_url":"https://api.github.com/repos/Malabarba/cider-nrepl/forks","keys_url":"https://api.github.com/repos/Malabarba/cider-nrepl/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Malabarba/cider-nrepl/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Malabarba/cider-nrepl/teams","hooks_url":"https://api.github.com/repos/Malabarba/cider-nrepl/hooks","issue_events_url":"https://api.github.com/repos/Malabarba/cider-nrepl/issues/events{/number}","events_url":"https://api.github.com/repos/Malabarba/cider-nrepl/events","assignees_url":"https://api.github.com/repos/Malabarba/cider-nrepl/assignees{/user}","branches_url":"https://api.github.com/repos/Malabarba/cider-nrepl/branches{/branch}","tags_url":"https://api.github.com/repos/Malabarba/cider-nrepl/tags","blobs_url":"https://api.github.com/repos/Malabarba/cider-nrepl/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Malabarba/cider-nrepl/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Malabarba/cider-nrepl/git/refs{/sha}","trees_url":"https://api.github.com/repos/Malabarba/cider-nrepl/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Malabarba/cider-nrepl/statuses/{sha}","languages_url":"https://api.github.com/repos/Malabarba/cider-nrepl/languages","stargazers_url":"https://api.github.com/repos/Malabarba/cider-nrepl/stargazers","contributors_url":"https://api.github.com/repos/Malabarba/cider-nrepl/contributors","subscribers_url":"https://api.github.com/repos/Malabarba/cider-nrepl/subscribers","subscription_url":"https://api.github.com/repos/Malabarba/cider-nrepl/subscription","commits_url":"https://api.github.com/repos/Malabarba/cider-nrepl/commits{/sha}","git_commits_url":"https://api.github.com/repos/Malabarba/cider-nrepl/git/commits{/sha}","comments_url":"https://api.github.com/repos/Malabarba/cider-nrepl/comments{/number}","issue_comment_url":"https://api.github.com/repos/Malabarba/cider-nrepl/issues/comments{/number}","contents_url":"https://api.github.com/repos/Malabarba/cider-nrepl/contents/{+path}","compare_url":"https://api.github.com/repos/Malabarba/cider-nrepl/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Malabarba/cider-nrepl/merges","archive_url":"https://api.github.com/repos/Malabarba/cider-nrepl/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Malabarba/cider-nrepl/downloads","issues_url":"https://api.github.com/repos/Malabarba/cider-nrepl/issues{/number}","pulls_url":"https://api.github.com/repos/Malabarba/cider-nrepl/pulls{/number}","milestones_url":"https://api.github.com/repos/Malabarba/cider-nrepl/milestones{/number}","notifications_url":"https://api.github.com/repos/Malabarba/cider-nrepl/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Malabarba/cider-nrepl/labels{/name}","releases_url":"https://api.github.com/repos/Malabarba/cider-nrepl/releases{/id}","created_at":"2015-03-13T17:28:50Z","updated_at":"2015-04-24T16:51:56Z","pushed_at":"2015-04-24T16:51:56Z","git_url":"git://github.com/Malabarba/cider-nrepl.git","ssh_url":"git@github.com:Malabarba/cider-nrepl.git","clone_url":"https://github.com/Malabarba/cider-nrepl.git","svn_url":"https://github.com/Malabarba/cider-nrepl","homepage":null,"size":616,"stargazers_count":0,"watchers_count":0,"language":"Clojure","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"clojure-emacs:master","ref":"master","sha":"91bc58c98665606c09a7f61808af2f0245f16b1f","user":{"login":"clojure-emacs","id":5080083,"avatar_url":"https://avatars.githubusercontent.com/u/5080083?v=3","gravatar_id":"","url":"https://api.github.com/users/clojure-emacs","html_url":"https://github.com/clojure-emacs","followers_url":"https://api.github.com/users/clojure-emacs/followers","following_url":"https://api.github.com/users/clojure-emacs/following{/other_user}","gists_url":"https://api.github.com/users/clojure-emacs/gists{/gist_id}","starred_url":"https://api.github.com/users/clojure-emacs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/clojure-emacs/subscriptions","organizations_url":"https://api.github.com/users/clojure-emacs/orgs","repos_url":"https://api.github.com/users/clojure-emacs/repos","events_url":"https://api.github.com/users/clojure-emacs/events{/privacy}","received_events_url":"https://api.github.com/users/clojure-emacs/received_events","type":"Organization","site_admin":false},"repo":{"id":15360927,"name":"cider-nrepl","full_name":"clojure-emacs/cider-nrepl","owner":{"login":"clojure-emacs","id":5080083,"avatar_url":"https://avatars.githubusercontent.com/u/5080083?v=3","gravatar_id":"","url":"https://api.github.com/users/clojure-emacs","html_url":"https://github.com/clojure-emacs","followers_url":"https://api.github.com/users/clojure-emacs/followers","following_url":"https://api.github.com/users/clojure-emacs/following{/other_user}","gists_url":"https://api.github.com/users/clojure-emacs/gists{/gist_id}","starred_url":"https://api.github.com/users/clojure-emacs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/clojure-emacs/subscriptions","organizations_url":"https://api.github.com/users/clojure-emacs/orgs","repos_url":"https://api.github.com/users/clojure-emacs/repos","events_url":"https://api.github.com/users/clojure-emacs/events{/privacy}","received_events_url":"https://api.github.com/users/clojure-emacs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/clojure-emacs/cider-nrepl","description":"nREPL middleware for CIDER","fork":false,"url":"https://api.github.com/repos/clojure-emacs/cider-nrepl","forks_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/forks","keys_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/keys{/key_id}","collaborators_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/teams","hooks_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/hooks","issue_events_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/issues/events{/number}","events_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/events","assignees_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/assignees{/user}","branches_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/branches{/branch}","tags_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/tags","blobs_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/git/refs{/sha}","trees_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/git/trees{/sha}","statuses_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/statuses/{sha}","languages_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/languages","stargazers_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/stargazers","contributors_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/contributors","subscribers_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/subscribers","subscription_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/subscription","commits_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/commits{/sha}","git_commits_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/git/commits{/sha}","comments_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/comments{/number}","issue_comment_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/issues/comments{/number}","contents_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/contents/{+path}","compare_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/compare/{base}...{head}","merges_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/merges","archive_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/downloads","issues_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/issues{/number}","pulls_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls{/number}","milestones_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/milestones{/number}","notifications_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/labels{/name}","releases_url":"https://api.github.com/repos/clojure-emacs/cider-nrepl/releases{/id}","created_at":"2013-12-21T15:27:38Z","updated_at":"2015-04-23T17:15:28Z","pushed_at":"2015-04-24T16:55:13Z","git_url":"git://github.com/clojure-emacs/cider-nrepl.git","ssh_url":"git@github.com:clojure-emacs/cider-nrepl.git","clone_url":"https://github.com/clojure-emacs/cider-nrepl.git","svn_url":"https://github.com/clojure-emacs/cider-nrepl","homepage":null,"size":1988,"stargazers_count":154,"watchers_count":154,"language":"Clojure","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":36,"mirror_url":null,"open_issues_count":13,"forks":36,"open_issues":13,"watchers":154,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/197"},"html":{"href":"https://github.com/clojure-emacs/cider-nrepl/pull/197"},"issue":{"href":"https://api.github.com/repos/clojure-emacs/cider-nrepl/issues/197"},"comments":{"href":"https://api.github.com/repos/clojure-emacs/cider-nrepl/issues/197/comments"},"review_comments":{"href":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/197/comments"},"review_comment":{"href":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/clojure-emacs/cider-nrepl/pulls/197/commits"},"statuses":{"href":"https://api.github.com/repos/clojure-emacs/cider-nrepl/statuses/6c40246cab89914e360180ced0608dc47c103b66"}}}}