Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CIDER locks up when printing large strings #1115

Closed
arrdem opened this issue Jun 5, 2015 · 56 comments
Closed

CIDER locks up when printing large strings #1115

arrdem opened this issue Jun 5, 2015 · 56 comments
Assignees

Comments

@arrdem
Copy link
Contributor

arrdem commented Jun 5, 2015

I have of late sacrificed many Emacsen to print lockup. Either due to nREPL network transport times or Emacs' known performance issues with long lines it's possible for a CIDER repl to freeze Emacs entirely such that it's not even possible to (kbd C-c C-c) or (kbd C-c C-b) to abort the print in progress. Killing Emacs is (obviously) a huge cramp on my workflow and it'd be awesome if this didn't happen.

<3

@bbatsov
Copy link
Member

bbatsov commented Jun 5, 2015

Might be related to #228. A reliable repro case and some quality time with the debugger/profiler should solve this.

@bbatsov bbatsov mentioned this issue Aug 7, 2015
6 tasks
@Malabarba
Copy link
Member

@arrdem About the keys you mentioned, did you try C-g too?

@bbatsov Emacs is notorious for being slow at font-locking long lines. I'd say the first thing to try is to not font-lock the output string if it's very long (don't know if that's been tried yet).

@arrdem
Copy link
Contributor Author

arrdem commented Aug 7, 2015

@Malabarba I would agree that this is more than likely Emacs' various long lines issues more than CIDER on further review. C-g locks up when I encounter this.

@bbatsov
Copy link
Member

bbatsov commented Aug 7, 2015

I don't think the problem's just font-locking related, although it's likely a good idea to disable font-locking for bigger results. There's something pretty wrong happening in the REPL with respect to output - one bigger result/output and it becomes nearly unusable. And this has been happening before the introduction of "fancy" font-locking for the results and the output.

@expez
Copy link
Member

expez commented Aug 8, 2015

About the keys you mentioned, did you try C-g too?

I have previously managed to stop this by spamming C-g along with cider-interrupt, but it took a long time before it registered my desire for that process to just go off and die.

@bbatsov
Copy link
Member

bbatsov commented Aug 9, 2015

@arrdem Btw, you do experience this problem only in the REPL or for interactive evaluation results as well?

@arichiardi
Copy link
Contributor

Confirm this

Malabarba referenced this issue Aug 9, 2015
Font-locking extremely long strings is pretty slow (and might generate
errors in some cases), so it's now conditional. This behavior is
adjustable via `cider-font-lock-max-length`.
@bbatsov
Copy link
Member

bbatsov commented Aug 9, 2015

Just noticed there's some fresh profiling data here. Seems our custom REPL implementation sucks big time...

@zarkone
Copy link
Contributor

zarkone commented Aug 17, 2015

I don't think it's about REPL, it's the same emacs long-line problem, or somehow connected with it. REPL buffer inserts the result with no new lines. For example, if i do cider-eval-last-sexp, i could spam C-g a few times to interrupt the process. But If I try cider-eval-last-sexp-and-replace, the situation would be the same, like i eval it in REPL buffer -- can't interrupt... I've tried to slurp 1,5M binary file, and after waiting some time with frozen Emacs i've seen the result -- long-lined result in REPL, and Emacs lagging because of it. So, the problem is reproducible not only in the REPL buffer.

I'll try to test interrupting with big text but without long lines.

@the-kenny
Copy link

I'm also running into this issue on a weekly-or-so basis. Very annoying.

One thing to note is that it gets better (i.e. emacs stays slightly more responsive), when truncate-lines is set to t. This disables visual line wrapping.

@mattiasw2
Copy link

If the missing new lines is the problem, a simple solution is to use clojure.pprint/pprint to print out the result value. How do I change the (cider)repl to do this?

@arrdem
Copy link
Contributor Author

arrdem commented Aug 15, 2016

@mattiasw2

M-x cider-repl-toggle-pretty-printing RET

Will in fact mostly mitigate this for many structures (nested maps etc) since the usual line length stays low enough that the REPL doesn't lock up.

Happy belated birthday to this issue >.>

I personally agree with @zarkone, this may well be Emacs' known problem with super long lines. Worth testing to see if this is worse than that, although the fact that it is possible to escape this hangup with kbd C-g suggests that it may well be part of the REPL code, rather than Emacs rendering or buffer implementation code.

@bbatsov
Copy link
Member

bbatsov commented Oct 7, 2016

Btw, do we have some profiling data regarding this? It'd be nice to know what should we aim to speed up/optimize...

@sooheon
Copy link

sooheon commented Oct 17, 2017

Even with toggle-truncate-lines and cider-repl-toggle-pretty-printing on, this problem has resurfaced with spec errors. There is no way to pretty print those, and if the :arg or :ret is a huge datastructure, emacs dies.

@gganley
Copy link
Contributor

gganley commented Mar 2, 2018

@sooheon Could you give an example of such a spec error?

@expez
Copy link
Member

expez commented Mar 2, 2018

@gganley Just create a spec requiring e.g. an int, and then pass it a gigantic clojure map. The entire map will be printed to show the erroneous value.

@gonewest818
Copy link
Contributor

Spending some time in the profiler with cider (master 18ed761) on Emacs 25.3.

In Emacs, toggle off

(toggle-truncate-lines)
(cider-repl-toggle-pretty-printing)

In the repl, disable

(set! *print-length* nil)
(set! *print-level* nil)

Output a long line

Start the profiler. Generate a long line in the repl

(range 10000)

this is the memory profile

screen shot 2018-03-10 at 8 00 28 am

and CPU profile

screen shot 2018-03-10 at 8 00 46 am

Notes:

  • cider-repl-show-maximum-output can be disabled with (setq cider-repl-scroll-on-output nil). Disabling does eliminate most of this extreme time and memory usage.
  • Nothing attributed to font locking?

Lag when long lines exist in the REPL

Now that this long line exists in the REPL there is the familiar lag. Just typing "return" at the prompt gets you the [=== ] spinner, Emacs is pegging a CPU at 100%, and this seems to hang indefinitely

screen shot 2018-03-10 at 8 19 55 am

I discovered I can interrupt this hang by typing any prefix that which-key knows how to complete, i.e. C-x or M- or whatever. At which point the prompt returns immediately.

In the profiler that looks like this. I'm going to type return, wait a few seconds, type M- and then C-g to abort the which-key popup.

screen shot 2018-03-10 at 8 36 49 am

screen shot 2018-03-10 at 8 36 57 am

I'm not convinced ido-kill-buffer has anything to do with this. If I invoke swiper on the repl while the spinner is spinning, followed by M- to get the spinner to stop, the profile looks like this.

screen shot 2018-03-10 at 8 42 10 am

@bbatsov
Copy link
Member

bbatsov commented Mar 10, 2018

cider-repl-show-maximum-output can be disabled with (setq cider-repl-scroll-on-output nil). Disabling does eliminate most of this extreme time and memory usage.

But at the cost of now scrolling to the end of the long output. :-)

Now that this long line exists in the REPL there is the familiar lag. Just typing "return" at the prompt gets you the [=== ] spinner, Emacs is pegging a CPU at 100%, and this seems to hang indefinitely

Hmm, seems you found some different bug (which should be simple to fix). The spinner gets triggered only while there's some evaluation in progress and just pressing return shouldn't trigger any evaluation. Looking at the profiler data I'm completely puzzled how ido gets involved in all of this.

As for a fix I've been thinking the following:

Results and output are streamed in chunks by nREPL (See https://github.com/clojure-emacs/cider/blob/master/cider-repl.el#L805). We can simply add a couple of running counters of the size of the result/output so far and when they reach some maximum we can offer users to truncate the long result (and maybe display the who result in a dedicated disposable buffer. We can also suggest users to remove the last output/result after they print it if it's something big.

And last but not least - we can borrow unrepl's idea of expandable (elided) collections. It prints the beginning of a (big) collection and clickable ellipsis to show you a bigger part of it. We can store in memory big results off-screen and attach some simple relation between a short version with ellipsis and the actual result. I think all of the above a relatively simple to implement and would be very appreciated by our users.

@gonewest818
Copy link
Contributor

gonewest818 commented Mar 10, 2018

Oh, which reminds me. Clearing the repl C-c C-o doesn’t work reliably in the buffer with the long line of output. I found I could get it to clear by M-< to the top and then clear the buffer from there. And once the repl buffer is cleared these lags go away. That’s how I’ve been resetting between tests. . Ignore this. I was just being dense.

@gonewest818
Copy link
Contributor

Hmm, seems you found some different bug (which should be simple to fix). The spinner gets triggered only while there's some evaluation in progress and just pressing return shouldn't trigger any evaluation.

Well, for some reason it is triggering an evaluation (of the newline?), see here

)
(-->
  id         "42"
  op         "eval"
  session    "3a9eedb7-77e7-48d0-840a-0e2c3f789dce"
  time-stamp "2018-03-10 11:48:54.055113000"
  code       "
"
  column     7
  file       "*cider-repl localhost*"
  line       57
  ns         "user"
)
(<--
  id         "42"
  session    "3a9eedb7-77e7-48d0-840a-0e2c3f789dce"
  time-stamp "2018-03-10 11:49:13.510875000"
  status     ("done")
)
(<--
  id                 "42"
  session            "3a9eedb7-77e7-48d0-840a-0e2c3f789dce"
  time-stamp         "2018-03-10 11:49:13.511287000"
  changed-namespaces (dict)
  repl-type          "clj"
  status             ("state")
)

I'll go track that down.

@gonewest818
Copy link
Contributor

So here's what I'm finding about the lag when long lines exist in the REPL. If I watch the *nrepl-messages...* buffer during these long lags, I see only the outbound "eval" message but no response. Only when I trigger the which-key completion as mentioned before, then finally I see return messages containing the result of the evaluation, the "done", and the "state". I'm evaluating simple integer constants like "1", so there's no reason the evaluations should take any time at all.

@bbatsov
Copy link
Member

bbatsov commented Mar 12, 2018

Hmm, that's extremely odd. Might be somehow related to the fact the REPL buffer is also the connection buffer, but I cannot think why the processing of the responses would halt and continue when you type something.

@gonewest818
Copy link
Contributor

gonewest818 commented Mar 12, 2018

Somehow related to the spinner itself. I just tried (setq cider-show-eval-spinner nil) with everything else as described earlier (including the long output line in the repl buffer), and so far I can't reproduce the hang. @Malabarba, any insights here?

@arrdem
Copy link
Contributor Author

arrdem commented Mar 14, 2018

Hummm I was able to repro this behavior using just spinner.el, in *scratch* doing (progn (start-spinner) (dotimes (i 100000) (insert-string "a")) (insert-string "\n\n") (stop-spinner)) which takes about ~7s and definitely hangs emacs for the duration. In the presence of long lines, the spinner seems to contribute significantly to Emacs' lag if it's allowed to continue but I didn't make an effort to dig into why.

@xiongtx
Copy link
Member

xiongtx commented Mar 14, 2018

Hummm I was able to repro this behavior using just spinner.el

The code you wrote to insert "a" 100,000 times will lock up Emacs for some time even without a spinner, so I'm not sure what it's supposed to demonstrate.

@bbatsov
Copy link
Member

bbatsov commented Mar 14, 2018

I was assuming the truncation is client side since there’s a possibility the evaluation has a side effect.. ?

I don't see how this would be a problem. The evaluation would still be complete, we'd just return only a portion of the result and some marker to be able to retrieve the full result (e.g. when an user presses ... in the truncated result). And I assume we'd do the same thing if we're doing things client-side. The slight advantage of the server-side approach would be that this will reduce the data we send to Emacs (and we have to decode) and that potentially other clients can benefit from this. The advantage of the client-side approach would be we won't have to mess with the eval op, but that's probably not a big deal.

@vspinu
Copy link
Contributor

vspinu commented Mar 14, 2018

FWIW this is a well known problem with emacs redisplay when long lines are present. It occurs in all buffers and it's way worse with truncate-lines non-nil. Just copy repl output into a fundamental buffer and you should observe slow edditing. The only solution (in my mind) is to truncate long lines in the process filter.

Spinner is not the root cause. It just triggers redisplay 10 times a seconds. Setting fps to 1 removes the problem.

As a replacement for the spinner making the last REPL prompt red would work for me, but please don't leave us without eval indicator.

@vspinu
Copy link
Contributor

vspinu commented Mar 14, 2018

The slight advantage of the server-side approach would be that this will reduce the data we send to Emacs (and we have to decode) and that potentially other clients can benefit from this.

It's a big advantage on remotes. One problem with the server side is that one would need to manage caching. Storing all output's so far doesn't make sense. Also I am not sure this should apply to *cider-results*. The client can have it hanging around for a while and clearing the server side cache might be unpleasant.

@bbatsov
Copy link
Member

bbatsov commented Mar 14, 2018

This should definitely not apply for *cider-results*. It should certainly be used in the REPL, and probably for interactive evals as well.

One problem with the server side is that one would need to manage caching. Storing all output's so far doesn't make sense.

I was thinking of storing just results/output that exceed some limit, but we can probably limit this just to the last result. The problem with not storing everything (either client or server-side) is that you won't be able to expand all the truncated results/output.

@gonewest818
Copy link
Contributor

gonewest818 commented Mar 14, 2018

I would bet people want access to the last N results, where N might not be "every result for all time" but it seems likely N is also greater than 1 for most people.

It suggests to me that the cache eviction should be directed by the client. Then the client is free to implement a "sliding window" policy with configurable N, keep just the last result (N=1), allow specific results to be "pinned" regardless where they are in the history, disable caching entirely (N=0) if it doesn't want to be bothered, etc.

@gonewest818 gonewest818 self-assigned this Mar 15, 2018
@gonewest818
Copy link
Contributor

fwiw I am working on this. I have a prototype middleware intercepting responses containing "value" or "pprint-out" and truncating those strings if their length exceeds some threshold. The middleware keeps a hash map of the full-length strings which can be retrieved or removed via middleware ops.

I'm moving now into cider to change the nrepl response handlers. Those will need to add a button whenever the response has been truncated, such that clicking the button will retrieve the full length result and display it (in a separate window, I'm not going to attempt folding). Finally I'll see to it that clearing these truncated lines of output from the repl will also clear the corresponding data in the middleware.

In principle this should prevent excessive network traffic from remote repls, as well as eliminate long lines in the repl buffer leading to other interactivity problems. The end goal is to make sure the middleware is not cider-specific so other tools can (if they choose) enable the truncation too.

@bbatsov
Copy link
Member

bbatsov commented Mar 20, 2018

Sounds awesome! 👍

fwiw I am working on this. I have a prototype middleware intercepting responses containing "value" or "pprint-out" and truncating those strings if their length exceeds some threshold. The middleware keeps a hash map of the full-length strings which can be retrieved or removed via middleware ops.

You should also consider out and err keys.

Just one small consideration - there should be some op to turn the interception on and off. I assume everyone will want it, but early version might have some bugs and it'd be nice if users can work around those without having to meddle with the middleware vector.

@vspinu
Copy link
Contributor

vspinu commented Mar 20, 2018

"pprint-out" and truncating those strings if their length exceeds some threshold.

Is it about truncating the length of individual lines or the whole output? If the latter, would be nice to elide the middle part of the output, keeping start and end for inspection. Especially useful for commands like cider-pprint-eval-last-sexp.

Thanks for working on this!

@gonewest818
Copy link
Contributor

@bbatsov - the middleware is disabled if the threshold length is nil.

@vspinu I agree, those would be useful. It's currently truncating the entire result, and by that I mean it blindly chops the result string at the specified length. There's no other smarts involved: no logic to elide elements of the collection in some logical way, no attempt to fold nested data structures, not even trying to preserve the closing braces. I'm going to finish a pass with this simplistic scheme and make sure the mechanics are sound. I might have to save any kind of sophisticated "elision" for a subsequent release.

@sooheon
Copy link

sooheon commented Mar 26, 2018

@gonewest818 something to consider when not preserving structure is that anyone with smartparens or lispy or the like enabled will likely face a ton of lag as the plugin tries to search for matching pairs.

@gonewest818
Copy link
Contributor

gonewest818 commented Mar 26, 2018 via email

@bbatsov
Copy link
Member

bbatsov commented Jul 29, 2018

Just saw this https://twitter.com/CursiveIDE/status/1023508436443529216 and got reminded of this ticket. @gonewest818 If you don't have time to wrap this up maybe you can at least push your code to some branch so someone else can take it over and the work won't be lost. That's definitely not a pressing concern, as we have our hands full with other tasks, but I think it'd be great if something like this was handled directly in nREPL itself. And now that's finally feasible. :-)

@behrica
Copy link
Contributor

behrica commented Sep 18, 2018

Just one comment from my side.

I am doing some type of NLP with clojure, so my data structures are by definition very long.
I work on them, in general, very successfully by using "specter" and only printing pieces and summaries of the data.

But each time I have a syntax error in my repl expression (missing parenthesis for example),
cider tries to print the whole data structure., which always hangs emacs.

This is very annoying.

I think we really need a,configurable, absolute limit on the length of "result" of a given repl expression cider is willing to print. (if "error", or "out", this should not matter)

For me it would be acceptable if it just "cuts" the long "result" in the middle, without paying any attention to structure.

@behrica
Copy link
Contributor

behrica commented Sep 18, 2018

To illustrate see this:

The following snippet has unmatched parenthesis:

(sp/select [sp/FIRST :experts sp/FIRST (sp/submap [:name  :cv-text  :doi-text]
                                                                       ] {:nonsense 123})
                                )

Trying to evaluate this in emacs it fails obviously, and
in the error message it somehow "prints" the full data structure in this case.
'{:nonsense 123}'
Even in a very strange way, in the middle of parts of the stacktrace.

RuntimeException Unmatched delimiter: ]  clojure.lang.Util.runtimeException (Util.java:221)
{:nonsense 123}RuntimeException Unmatched delimiter: )  clojure.lang.Util.runtimeException (Util.java:221)
RuntimeException Unmatched delimiter: )  clojure.lang.Util.runtimeException (Util.java:221)

which results in a hanging emacs immediately.

@behrica
Copy link
Contributor

behrica commented Sep 25, 2018

I have found an other potential work around to the problem of large strings-

In my work with clojure for analyzing (text) data, I noticed that I hardly ever want to print large strings in full.

So one way of solving the large string problem, is to think about using by default a pretty printer,
which prints strings always truncated.

I changed for this purpose the implementation of fipp, so that it truncates all strings to 10 characters and then prints the string length in brackets.

This has a a side effect that most nested maps / text structures are very readable in repl, like this:

 {:id "684415",
  :name "PLH Panel ...[21],
  :experts ({:name "BRAGARD C ...[16],
             :doi-link "../../../ ...[165],
             :cv-link "../../../ ...[188],
             :doi #object["[B" "0x736e343 ...[12] "[B@736e34 ...[13]],
             :cv #object["[B" "0x5ba0ad4 ...[12] "[B@5ba0ad ...[13]],
             :doi-text "PLH = Pla ...[7546],
             :cv-text "CURRICULU ...[4926]}
            {:name "DEHNEN-SC ...[26],
             :doi-link "../../../ ...[165],
             :cv-link "../../../ ...[188],
             :doi #object["[B" "0x1f56d4f ...[12] "[B@1f56d4 ...[13]],
             :cv #object["[B" "0x4be0125 ...[12] "[B@4be012 ...[13]],
             :doi-text "PLH = Pla ...[5553],
             :cv-text "CURRICULU ...[4479]}

Combining this with using print-length and print-level nearly guaranties that the the output stays reasonable short.

I was even thinking that clojure.core should get a var like print-string-length,
as the current print-length and print-level do not always full its purpose of keeping the size of printed data structures small.

In case I really want to see a string in full length, I could then use (print ) or (pprint ) directly.
(or switch cider to non-pretty-printing)

Ideally the fipp library would have a at runtime configurable way to control the string truncation.

Any opinion on this ?

@behrica
Copy link
Contributor

behrica commented Sep 27, 2018

Another, rather easy solution, to the large string problem is to set a specific 'print-method' for strings.

The following code does this:

(defn shorten-string [s]
   (if (> (count s) 100)
     (str (.substring s 0 100) " ...[" (count s)    "]")
     s))
(defmethod print-method java.lang.String [v ^java.io.Writer w]  (.write w (shorten-string  v)))

I combine this typically with a method to truncate the overall length of the result of a REPL evaluation to 1000, see my comment on #1934

Both methods together give a flexible way to safely explore even larger data structures in clojure / cider.

@behrica
Copy link
Contributor

behrica commented Oct 6, 2018

Just to give my conclusion on this problem.

I experimented a lot in solving the long-string problem, and I came to the conclusion that by combining to set *print-length* , *print-level* ,the usage of cider pretty-printing and customizing the print-method function of java.lang.String via

(defmethod print-method java.lang.String [v ^java.io.Writer w]  (.write w (shorten-string  v)))

the problem of too long cider-repl outputs (including very long Strings) can be nearly eliminated completely.

It is rather convenient already now in the repl to change quickly the settings of

  • *print-length*
  • *print-level*
  • toggle pretty printing

To have a convenient way to control the string truncation, two simple elisp function can be used, which inject into the repl the clojure code to control the printing of java.lang.String:

  (defun cider-pr-shorten-string (max)
    (interactive "nShorten strings to ?:  ")
    (insert (format "
(defn shorten-string [s]
   (if (> (count s) %d)
     (str (.substring s 0 %d) \" ...[\" (count s)    \"]\")
     s))
(defmethod print-method java.lang.String [v ^java.io.Writer w]  (.write w (shorten-string  v)))"
		    max max)  )
    
    (cider-repl-return))

  (defun cider-pr-normal-string ()
    (interactive)
    (insert "
(defmethod print-method java.lang.String [v ^java.io.Writer w]  (.write w v))
")
    (cider-repl-return))

This should nearly guaranty that the evaluation of clojure expressions never returns too long output.

The "shorten" function prints the length of the string at the end, so it is rather easy to see, how long the string would have been, if printed.
The two elisp functions above allow then to quickly set the truncation length, as sometimes the print is required.

@stale
Copy link

stale bot commented May 8, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contribution and understanding!

@stale stale bot added the stale label May 8, 2019
@bbatsov
Copy link
Member

bbatsov commented May 11, 2019

That's mostly solved on CIDER 0.21+, so I'll close this ticket.

@bbatsov bbatsov closed this as completed May 11, 2019
@jumarko
Copy link

jumarko commented Sep 19, 2019

UPDATE: cider version 0.22.1-snapshot and Emacs 26.3; Mac OS X 10.14.6; JDK 11

If I try to print a long string a couple of times the REPL still does get significantly slower.
Just tried this:

(println full-github-payload)

(println full-github-payload)

;; this time the evaluation itself took significantly longer!
(println full-github-payload)

;; REPL buffer is almost unusable at this point - even for simple things like:
(+ 10 20)
;;=> ... waiting for many seconds...

full-github-payload for the reference:

(def full-github-payload
    {:action "synchronize", ;; 'synchronize' when new changes are pushed to the pull request's branch
     :number 1,

     ;; pull request
     :pull_request
     {:html_url "https://github.com/jumarko/poptavka/pull/1",
      :merge_commit_sha "be827754d3af94121d0983bc3b36f3466d089528",
      :mergeable_state "unknown",
      :mergeable nil,
      :patch_url "https://github.com/jumarko/poptavka/pull/1.patch",
      :labels [],
      :assignees [],
      :additions 2735,
      :closed_at nil,
      :merged false,
      :review_comment_url "https://api.github.com/repos/jumarko/poptavka/pulls/comments{/number}",
      :author_association "OWNER",
      :number 1,
      :milestone nil,
      :requested_reviewers [],
      :comments 1,
      :node_id "MDExOlB1bGxSZXF1ZXN0MjkyODY0Mzkx",
      :merged_at nil,
      :statuses_url
      "https://api.github.com/repos/jumarko/poptavka/statuses/c4c5320450381fcd20a980eb8a311910de52f7e2",
      :state "open",
      :changed_files 9,
      :issue_url "https://api.github.com/repos/jumarko/poptavka/issues/1",
      :title "Juraj delta",
      :commits_url "https://api.github.com/repos/jumarko/poptavka/pulls/1/commits",
      :updated_at "2019-07-11T14:10:58Z",
      :head
      {:label "jumarko:juraj-delta",
       :ref "juraj-delta",
       :sha "c4c5320450381fcd20a980eb8a311910de52f7e2",
       :user
       {:html_url "https://github.com/jumarko",
        :gravatar_id "",
        :followers_url "https://api.github.com/users/jumarko/followers",
        :subscriptions_url "https://api.github.com/users/jumarko/subscriptions",
        :site_admin false,
        :following_url "https://api.github.com/users/jumarko/following{/other_user}",
        :node_id "MDQ6VXNlcjEwODM2Mjk=",
        :type "User",
        :received_events_url "https://api.github.com/users/jumarko/received_events",
        :login "jumarko",
        :organizations_url "https://api.github.com/users/jumarko/orgs",
        :id 1083629,
        :events_url "https://api.github.com/users/jumarko/events{/privacy}",
        :url "https://api.github.com/users/jumarko",
        :repos_url "https://api.github.com/users/jumarko/repos",
        :starred_url "https://api.github.com/users/jumarko/starred{/owner}{/repo}",
        :gists_url "https://api.github.com/users/jumarko/gists{/gist_id}",
        :avatar_url "https://avatars0.githubusercontent.com/u/1083629?v=4"},
       :repo
       {:html_url "https://github.com/jumarko/poptavka",
        :description "Repository for my former free-time project \"poptavka\"",
        :archived false,
        :open_issues_count 1,
        :watchers 0,
        :ssh_url "git@github.com:jumarko/poptavka.git",
        :hooks_url "https://api.github.com/repos/jumarko/poptavka/hooks",
        :archive_url "https://api.github.com/repos/jumarko/poptavka/{archive_format}{/ref}",
        :keys_url "https://api.github.com/repos/jumarko/poptavka/keys{/key_id}",
        :forks_count 1,
        :languages_url "https://api.github.com/repos/jumarko/poptavka/languages",
        :git_url "git://github.com/jumarko/poptavka.git",
        :issue_comment_url "https://api.github.com/repos/jumarko/poptavka/issues/comments{/number}",
        :git_refs_url "https://api.github.com/repos/jumarko/poptavka/git/refs{/sha}",
        :clone_url "https://github.com/jumarko/poptavka.git",
        :contents_url "https://api.github.com/repos/jumarko/poptavka/contents/{+path}",
        :has_downloads true,
        :teams_url "https://api.github.com/repos/jumarko/poptavka/teams",
        :has_issues true,
        :disabled false,
        :issue_events_url "https://api.github.com/repos/jumarko/poptavka/issues/events{/number}",
        :license nil,
        :private false,
        :watchers_count 0,
        :collaborators_url
        "https://api.github.com/repos/jumarko/poptavka/collaborators{/collaborator}",
        :homepage nil,
        :git_commits_url "https://api.github.com/repos/jumarko/poptavka/git/commits{/sha}",
        :name "poptavka",
        :releases_url "https://api.github.com/repos/jumarko/poptavka/releases{/id}",
        :milestones_url "https://api.github.com/repos/jumarko/poptavka/milestones{/number}",
        :svn_url "https://github.com/jumarko/poptavka",
        :node_id "MDEwOlJlcG9zaXRvcnk4OTI0NDY1MQ==",
        :merges_url "https://api.github.com/repos/jumarko/poptavka/merges",
        :compare_url "https://api.github.com/repos/jumarko/poptavka/compare/{base}...{head}",
        :stargazers_count 0,
        :tags_url "https://api.github.com/repos/jumarko/poptavka/tags",
        :statuses_url "https://api.github.com/repos/jumarko/poptavka/statuses/{sha}",
        :notifications_url
        "https://api.github.com/repos/jumarko/poptavka/notifications{?since,all,participating}",
        :open_issues 1,
        :has_wiki true,
        :size 12974,
        :assignees_url "https://api.github.com/repos/jumarko/poptavka/assignees{/user}",
        :commits_url "https://api.github.com/repos/jumarko/poptavka/commits{/sha}",
        :labels_url "https://api.github.com/repos/jumarko/poptavka/labels{/name}",
        :forks_url "https://api.github.com/repos/jumarko/poptavka/forks",
        :contributors_url "https://api.github.com/repos/jumarko/poptavka/contributors",
        :updated_at "2017-04-24T13:59:28Z",
        :pulls_url "https://api.github.com/repos/jumarko/poptavka/pulls{/number}",
        :has_pages false,
        :default_branch "master",
        :language "Java",
        :comments_url "https://api.github.com/repos/jumarko/poptavka/comments{/number}",
        :id 89244651,
        :stargazers_url "https://api.github.com/repos/jumarko/poptavka/stargazers",
        :issues_url "https://api.github.com/repos/jumarko/poptavka/issues{/number}",
        :trees_url "https://api.github.com/repos/jumarko/poptavka/git/trees{/sha}",
        :events_url "https://api.github.com/repos/jumarko/poptavka/events",
        :branches_url "https://api.github.com/repos/jumarko/poptavka/branches{/branch}",
        :url "https://api.github.com/repos/jumarko/poptavka",
        :downloads_url "https://api.github.com/repos/jumarko/poptavka/downloads",
        :forks 1,
        :subscribers_url "https://api.github.com/repos/jumarko/poptavka/subscribers",
        :full_name "jumarko/poptavka",
        :blobs_url "https://api.github.com/repos/jumarko/poptavka/git/blobs{/sha}",
        :subscription_url "https://api.github.com/repos/jumarko/poptavka/subscription",
        :fork false,
        :deployments_url "https://api.github.com/repos/jumarko/poptavka/deployments",
        :has_projects true,
        :pushed_at "2019-07-11T14:10:58Z",
        :owner
        {:html_url "https://github.com/jumarko",
         :gravatar_id "",
         :followers_url "https://api.github.com/users/jumarko/followers",
         :subscriptions_url "https://api.github.com/users/jumarko/subscriptions",
         :site_admin false,
         :following_url "https://api.github.com/users/jumarko/following{/other_user}",
         :node_id "MDQ6VXNlcjEwODM2Mjk=",
         :type "User",
         :received_events_url "https://api.github.com/users/jumarko/received_events",
         :login "jumarko",
         :organizations_url "https://api.github.com/users/jumarko/orgs",
         :id 1083629,
         :events_url "https://api.github.com/users/jumarko/events{/privacy}",
         :url "https://api.github.com/users/jumarko",
         :repos_url "https://api.github.com/users/jumarko/repos",
         :starred_url "https://api.github.com/users/jumarko/starred{/owner}{/repo}",
         :gists_url "https://api.github.com/users/jumarko/gists{/gist_id}",
         :avatar_url "https://avatars0.githubusercontent.com/u/1083629?v=4"},
        :git_tags_url "https://api.github.com/repos/jumarko/poptavka/git/tags{/sha}",
        :created_at "2017-04-24T13:40:09Z",
        :mirror_url nil}},
      :diff_url "https://github.com/jumarko/poptavka/pull/1.diff",
      :draft false,
      :maintainer_can_modify false,
      :comments_url "https://api.github.com/repos/jumarko/poptavka/issues/1/comments",
      :deletions 38,
      :locked false,
      :id 292864391,
      :rebaseable nil,
      :commits 17,
      :url "https://api.github.com/repos/jumarko/poptavka/pulls/1",
      :review_comments 0,
      :base
      {:label "jumarko:master",
       :ref "master",
       :sha "c81331dfd6eec6a248c3e0da76ad4c53494b9f59",
       :user
       {:html_url "https://github.com/jumarko",
        :gravatar_id "",
        :followers_url "https://api.github.com/users/jumarko/followers",
        :subscriptions_url "https://api.github.com/users/jumarko/subscriptions",
        :site_admin false,
        :following_url "https://api.github.com/users/jumarko/following{/other_user}",
        :node_id "MDQ6VXNlcjEwODM2Mjk=",
        :type "User",
        :received_events_url "https://api.github.com/users/jumarko/received_events",
        :login "jumarko",
        :organizations_url "https://api.github.com/users/jumarko/orgs",
        :id 1083629,
        :events_url "https://api.github.com/users/jumarko/events{/privacy}",
        :url "https://api.github.com/users/jumarko",
        :repos_url "https://api.github.com/users/jumarko/repos",
        :starred_url "https://api.github.com/users/jumarko/starred{/owner}{/repo}",
        :gists_url "https://api.github.com/users/jumarko/gists{/gist_id}",
        :avatar_url "https://avatars0.githubusercontent.com/u/1083629?v=4"},
       :repo
       {:html_url "https://github.com/jumarko/poptavka",
        :description "Repository for my former free-time project \"poptavka\"",
        :archived false,
        :open_issues_count 1,
        :watchers 0,
        :ssh_url "git@github.com:jumarko/poptavka.git",
        :hooks_url "https://api.github.com/repos/jumarko/poptavka/hooks",
        :archive_url "https://api.github.com/repos/jumarko/poptavka/{archive_format}{/ref}",
        :keys_url "https://api.github.com/repos/jumarko/poptavka/keys{/key_id}",
        :forks_count 1,
        :languages_url "https://api.github.com/repos/jumarko/poptavka/languages",
        :git_url "git://github.com/jumarko/poptavka.git",
        :issue_comment_url "https://api.github.com/repos/jumarko/poptavka/issues/comments{/number}",
        :git_refs_url "https://api.github.com/repos/jumarko/poptavka/git/refs{/sha}",
        :clone_url "https://github.com/jumarko/poptavka.git",
        :contents_url "https://api.github.com/repos/jumarko/poptavka/contents/{+path}",
        :has_downloads true,
        :teams_url "https://api.github.com/repos/jumarko/poptavka/teams",
        :has_issues true,
        :disabled false,
        :issue_events_url "https://api.github.com/repos/jumarko/poptavka/issues/events{/number}",
        :license nil,
        :private false,
        :watchers_count 0,
        :collaborators_url
        "https://api.github.com/repos/jumarko/poptavka/collaborators{/collaborator}",
        :homepage nil,
        :git_commits_url "https://api.github.com/repos/jumarko/poptavka/git/commits{/sha}",
        :name "poptavka",
        :releases_url "https://api.github.com/repos/jumarko/poptavka/releases{/id}",
        :milestones_url "https://api.github.com/repos/jumarko/poptavka/milestones{/number}",
        :svn_url "https://github.com/jumarko/poptavka",
        :node_id "MDEwOlJlcG9zaXRvcnk4OTI0NDY1MQ==",
        :merges_url "https://api.github.com/repos/jumarko/poptavka/merges",
        :compare_url "https://api.github.com/repos/jumarko/poptavka/compare/{base}...{head}",
        :stargazers_count 0,
        :tags_url "https://api.github.com/repos/jumarko/poptavka/tags",
        :statuses_url "https://api.github.com/repos/jumarko/poptavka/statuses/{sha}",
        :notifications_url
        "https://api.github.com/repos/jumarko/poptavka/notifications{?since,all,participating}",
        :open_issues 1,
        :has_wiki true,
        :size 12974,
        :assignees_url "https://api.github.com/repos/jumarko/poptavka/assignees{/user}",
        :commits_url "https://api.github.com/repos/jumarko/poptavka/commits{/sha}",
        :labels_url "https://api.github.com/repos/jumarko/poptavka/labels{/name}",
        :forks_url "https://api.github.com/repos/jumarko/poptavka/forks",
        :contributors_url "https://api.github.com/repos/jumarko/poptavka/contributors",
        :updated_at "2017-04-24T13:59:28Z",
        :pulls_url "https://api.github.com/repos/jumarko/poptavka/pulls{/number}",
        :has_pages false,
        :default_branch "master",
        :language "Java",
        :comments_url "https://api.github.com/repos/jumarko/poptavka/comments{/number}",
        :id 89244651,
        :stargazers_url "https://api.github.com/repos/jumarko/poptavka/stargazers",
        :issues_url "https://api.github.com/repos/jumarko/poptavka/issues{/number}",
        :trees_url "https://api.github.com/repos/jumarko/poptavka/git/trees{/sha}",
        :events_url "https://api.github.com/repos/jumarko/poptavka/events",
        :branches_url "https://api.github.com/repos/jumarko/poptavka/branches{/branch}",
        :url "https://api.github.com/repos/jumarko/poptavka",
        :downloads_url "https://api.github.com/repos/jumarko/poptavka/downloads",
        :forks 1,
        :subscribers_url "https://api.github.com/repos/jumarko/poptavka/subscribers",
        :full_name "jumarko/poptavka",
        :blobs_url "https://api.github.com/repos/jumarko/poptavka/git/blobs{/sha}",
        :subscription_url "https://api.github.com/repos/jumarko/poptavka/subscription",
        :fork false,
        :deployments_url "https://api.github.com/repos/jumarko/poptavka/deployments",
        :has_projects true,
        :pushed_at "2019-07-11T14:10:58Z",
        :owner
        {:html_url "https://github.com/jumarko",
         :gravatar_id "",
         :followers_url "https://api.github.com/users/jumarko/followers",
         :subscriptions_url "https://api.github.com/users/jumarko/subscriptions",
         :site_admin false,
         :following_url "https://api.github.com/users/jumarko/following{/other_user}",
         :node_id "MDQ6VXNlcjEwODM2Mjk=",
         :type "User",
         :received_events_url "https://api.github.com/users/jumarko/received_events",
         :login "jumarko",
         :organizations_url "https://api.github.com/users/jumarko/orgs",
         :id 1083629,
         :events_url "https://api.github.com/users/jumarko/events{/privacy}",
         :url "https://api.github.com/users/jumarko",
         :repos_url "https://api.github.com/users/jumarko/repos",
         :starred_url "https://api.github.com/users/jumarko/starred{/owner}{/repo}",
         :gists_url "https://api.github.com/users/jumarko/gists{/gist_id}",
         :avatar_url "https://avatars0.githubusercontent.com/u/1083629?v=4"},
        :git_tags_url "https://api.github.com/repos/jumarko/poptavka/git/tags{/sha}",
        :created_at "2017-04-24T13:40:09Z",
        :mirror_url nil}},
      :_links
      {:self {:href "https://api.github.com/repos/jumarko/poptavka/pulls/1"},
       :html {:href "https://github.com/jumarko/poptavka/pull/1"},
       :issue {:href "https://api.github.com/repos/jumarko/poptavka/issues/1"},
       :comments {:href "https://api.github.com/repos/jumarko/poptavka/issues/1/comments"},
       :review_comments {:href "https://api.github.com/repos/jumarko/poptavka/pulls/1/comments"},
       :review_comment {:href "https://api.github.com/repos/jumarko/poptavka/pulls/comments{/number}"},
       :commits {:href "https://api.github.com/repos/jumarko/poptavka/pulls/1/commits"},
       :statuses
       {:href
        "https://api.github.com/repos/jumarko/poptavka/statuses/c4c5320450381fcd20a980eb8a311910de52f7e2"}},
      :body "Trying to test delta analysis",
      :merged_by nil,
      :user
      {:html_url "https://github.com/jumarko",
       :gravatar_id "",
       :followers_url "https://api.github.com/users/jumarko/followers",
       :subscriptions_url "https://api.github.com/users/jumarko/subscriptions",
       :site_admin false,
       :following_url "https://api.github.com/users/jumarko/following{/other_user}",
       :node_id "MDQ6VXNlcjEwODM2Mjk=",
       :type "User",
       :received_events_url "https://api.github.com/users/jumarko/received_events",
       :login "jumarko",
       :organizations_url "https://api.github.com/users/jumarko/orgs",
       :id 1083629,
       :events_url "https://api.github.com/users/jumarko/events{/privacy}",
       :url "https://api.github.com/users/jumarko",
       :repos_url "https://api.github.com/users/jumarko/repos",
       :starred_url "https://api.github.com/users/jumarko/starred{/owner}{/repo}",
       :gists_url "https://api.github.com/users/jumarko/gists{/gist_id}",
       :avatar_url "https://avatars0.githubusercontent.com/u/1083629?v=4"},
      :review_comments_url "https://api.github.com/repos/jumarko/poptavka/pulls/1/comments",
      :requested_teams [],
      :assignee nil,
      :created_at "2019-06-28T14:58:08Z"},

     ;; timestamps
     :before "e42e0bc447064612e73bb5dc416265298accd9b4",
     :after "c4c5320450381fcd20a980eb8a311910de52f7e2",

     ;; repository
     :repository
     {:html_url "https://github.com/jumarko/poptavka",
      :description "Repository for my former free-time project \"poptavka\"",
      :archived false,
      :open_issues_count 1,
      :watchers 0,
      :ssh_url "git@github.com:jumarko/poptavka.git",
      :hooks_url "https://api.github.com/repos/jumarko/poptavka/hooks",
      :archive_url "https://api.github.com/repos/jumarko/poptavka/{archive_format}{/ref}",
      :keys_url "https://api.github.com/repos/jumarko/poptavka/keys{/key_id}",
      :forks_count 1,
      :languages_url "https://api.github.com/repos/jumarko/poptavka/languages",
      :git_url "git://github.com/jumarko/poptavka.git",
      :issue_comment_url "https://api.github.com/repos/jumarko/poptavka/issues/comments{/number}",
      :git_refs_url "https://api.github.com/repos/jumarko/poptavka/git/refs{/sha}",
      :clone_url "https://github.com/jumarko/poptavka.git",
      :contents_url "https://api.github.com/repos/jumarko/poptavka/contents/{+path}",
      :has_downloads true,
      :teams_url "https://api.github.com/repos/jumarko/poptavka/teams",
      :has_issues true,
      :disabled false,
      :issue_events_url "https://api.github.com/repos/jumarko/poptavka/issues/events{/number}",
      :license nil,
      :private false,
      :watchers_count 0,
      :collaborators_url "https://api.github.com/repos/jumarko/poptavka/collaborators{/collaborator}",
      :homepage nil,
      :git_commits_url "https://api.github.com/repos/jumarko/poptavka/git/commits{/sha}",
      :name "poptavka",
      :releases_url "https://api.github.com/repos/jumarko/poptavka/releases{/id}",
      :milestones_url "https://api.github.com/repos/jumarko/poptavka/milestones{/number}",
      :svn_url "https://github.com/jumarko/poptavka",
      :node_id "MDEwOlJlcG9zaXRvcnk4OTI0NDY1MQ==",
      :merges_url "https://api.github.com/repos/jumarko/poptavka/merges",
      :compare_url "https://api.github.com/repos/jumarko/poptavka/compare/{base}...{head}",
      :stargazers_count 0,
      :tags_url "https://api.github.com/repos/jumarko/poptavka/tags",
      :statuses_url "https://api.github.com/repos/jumarko/poptavka/statuses/{sha}",
      :notifications_url
      "https://api.github.com/repos/jumarko/poptavka/notifications{?since,all,participating}",
      :open_issues 1,
      :has_wiki true,
      :size 12974,
      :assignees_url "https://api.github.com/repos/jumarko/poptavka/assignees{/user}",
      :commits_url "https://api.github.com/repos/jumarko/poptavka/commits{/sha}",
      :labels_url "https://api.github.com/repos/jumarko/poptavka/labels{/name}",
      :forks_url "https://api.github.com/repos/jumarko/poptavka/forks",
      :contributors_url "https://api.github.com/repos/jumarko/poptavka/contributors",
      :updated_at "2017-04-24T13:59:28Z",
      :pulls_url "https://api.github.com/repos/jumarko/poptavka/pulls{/number}",
      :has_pages false,
      :default_branch "master",
      :language "Java",
      :comments_url "https://api.github.com/repos/jumarko/poptavka/comments{/number}",
      :id 89244651,
      :stargazers_url "https://api.github.com/repos/jumarko/poptavka/stargazers",
      :issues_url "https://api.github.com/repos/jumarko/poptavka/issues{/number}",
      :trees_url "https://api.github.com/repos/jumarko/poptavka/git/trees{/sha}",
      :events_url "https://api.github.com/repos/jumarko/poptavka/events",
      :branches_url "https://api.github.com/repos/jumarko/poptavka/branches{/branch}",
      :url "https://api.github.com/repos/jumarko/poptavka",
      :downloads_url "https://api.github.com/repos/jumarko/poptavka/downloads",
      :forks 1,
      :subscribers_url "https://api.github.com/repos/jumarko/poptavka/subscribers",
      :full_name "jumarko/poptavka",
      :blobs_url "https://api.github.com/repos/jumarko/poptavka/git/blobs{/sha}",
      :subscription_url "https://api.github.com/repos/jumarko/poptavka/subscription",
      :fork false,
      :deployments_url "https://api.github.com/repos/jumarko/poptavka/deployments",
      :has_projects true,
      :pushed_at "2019-07-11T14:10:58Z",
      :owner
      {:html_url "https://github.com/jumarko",
       :gravatar_id "",
       :followers_url "https://api.github.com/users/jumarko/followers",
       :subscriptions_url "https://api.github.com/users/jumarko/subscriptions",
       :site_admin false,
       :following_url "https://api.github.com/users/jumarko/following{/other_user}",
       :node_id "MDQ6VXNlcjEwODM2Mjk=",
       :type "User",
       :received_events_url "https://api.github.com/users/jumarko/received_events",
       :login "jumarko",
       :organizations_url "https://api.github.com/users/jumarko/orgs",
       :id 1083629,
       :events_url "https://api.github.com/users/jumarko/events{/privacy}",
       :url "https://api.github.com/users/jumarko",
       :repos_url "https://api.github.com/users/jumarko/repos",
       :starred_url "https://api.github.com/users/jumarko/starred{/owner}{/repo}",
       :gists_url "https://api.github.com/users/jumarko/gists{/gist_id}",
       :avatar_url "https://avatars0.githubusercontent.com/u/1083629?v=4"},
      :git_tags_url "https://api.github.com/repos/jumarko/poptavka/git/tags{/sha}",
      :created_at "2017-04-24T13:40:09Z",
      :mirror_url nil},

     ;; sender
     :sender
     {:html_url "https://github.com/jumarko",
      :gravatar_id "",
      :followers_url "https://api.github.com/users/jumarko/followers",
      :subscriptions_url "https://api.github.com/users/jumarko/subscriptions",
      :site_admin false,
      :following_url "https://api.github.com/users/jumarko/following{/other_user}",
      :node_id "MDQ6VXNlcjEwODM2Mjk=",
      :type "User",
      :received_events_url "https://api.github.com/users/jumarko/received_events",
      :login "jumarko",
      :organizations_url "https://api.github.com/users/jumarko/orgs",
      :id 1083629,
      :events_url "https://api.github.com/users/jumarko/events{/privacy}",
      :url "https://api.github.com/users/jumarko",
      :repos_url "https://api.github.com/users/jumarko/repos",
      :starred_url "https://api.github.com/users/jumarko/starred{/owner}{/repo}",
      :gists_url "https://api.github.com/users/jumarko/gists{/gist_id}",
      :avatar_url "https://avatars0.githubusercontent.com/u/1083629?v=4"}})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests