#clojure log - Jun 05 2014

The Joy of Clojure
Main Clojure site
Google Group
List of all logged dates

0:01 dbasch: j0ni: you either want to exclude the version from capacitor, or use that version instead of the newer one

3:01 Lajjla: em-dash, I approve of your name.

3:01 Now, how shall we use this information to conquer the world.

3:02 em-dash: um, typo nerd? or bot?

3:02 * em-dash self-identifies as a wannabe typo nerd

3:03 Lajjla: em-dash, nahh, just trying to look intelligent by using them.

3:05 em-dash: which is nice… plus they look nicer than hyphens. by which I probably mean more ‘distinguished’, aka trying to look intelligent

3:05 Lajjla: Indeed

3:05 you and I are much alike.

3:05 So, assume the position and surrender your eye socket, we will make merry love.

4:39 noncom: does anyone know if zach oakes ever visits this place?

4:42 clgv: noncom: dont remember seeing his name here during usual european day time

4:58 TEttinger: noncom: is he the guy behind play-clj, nightcode, and a bunch of other neat clojure tools?

4:59 AFAICT he doesn't use IRC

5:08 noncom: yeah, that very guy. wanted to talk with him about play-clj

5:08 so guess gotta go get him over reddit since it is pointed to at his website

5:13 clgv: noncom: email? ;)

5:15 TEttinger: yeah, play-clj is nice

5:15 I used it

5:15 noncom: oh, right, email :) there is the address on his github page

5:16 i want to use libgdx. i like the "bining" part of play-clj, but i am not rather sure i like the workflow that it enforces

5:16 i mean, it is strictly functional. and that also makes it slower

5:17 i wanted to understand, to which extent is it possible to use it with mutual state

5:22 TEttinger: how was your experience? did not you feel it somewhat architecturally limiting?

5:27 TEttinger: i felt that way at first

5:27 it's easy to make your own whatever

5:27 which is what i did for the unusual map i needed to render

5:29 I'd imagine Morgawr's thing will be better for this in the long run

5:29 https://github.com/Morgawr/Cloister-engine

5:31 noncom: TEttinger: oh, cloister is on slick..

5:32 can't take this one, since full 3d opengl is needed, and libgdx is a very advanced thing there

5:32 so i guess that i will have to write my own binding for it..

5:32 suiting te needs

5:32 hence fragmentation of the ecosystem..

5:32 oh well...

5:39 TEttinger: talk to oakes first, noncom

5:39 noncom: yeah, gonna try that out

5:40 TEttinger: in my experience clojure is just not very fast for real-time games... price you pay for such abstraction

5:42 noncom: yeah, i understand, but it can be rather good if treated properly. the uber-functional way of clojure community mainstream does not play with it well

5:43 so i have to use the so unwelcomed mutable state

5:43 TEttinger: oh yes

5:43 noncom: where needed

5:43 TEttinger: that is what happened to me

5:43 I spent so much time micro-optimizing

5:43 when I could have been blissfully writing C#

5:43 noncom: haha)

5:43 TEttinger: I was porting a C# program to clojure

5:44 noncom: so what you came up with? what were your thoughts on this and conclusions

5:44 TEttinger: the C# got a lot further in less time

5:44 noncom: what kind of game?

5:44 TEttinger: RPG/roguelike

5:44 I made a wallpaper out of it https://dl.dropboxusercontent.com/u/11914692/dungeon-wallpaper.png

5:45 noncom: reminds me of graphical nethack

5:45 so, clojure was slow even for that kind of game??

5:45 lazybot: noncom: Definitely not.

5:45 TEttinger: haha the sprites are from nethack

5:45 yeah, if I kept maps small it was OK

5:46 but if they got above like 40x40, then I started having monster pathfinding slowdowns, various calculations slowing down as they played out every movement...

5:47 large parts were in java as well

5:47 noncom: hmm i think that if you would use enough mutable state and caching, that would not've been the case

5:47 TEttinger: I got good speedup by offloading level gen into a second thread with a promise

5:47 or was it a future?

5:48 mutable state actually slowed down the program at one point when I had a plain array of java sprite objects

5:49 they I believe couldn't be disposed

5:49 noncom: hmmm

5:49 TEttinger: I really hammered at it

5:50 noncom: so you think that clojure can have this large impact on performance?

5:50 TEttinger: spent way too much time trying to make it fast

5:50 noncom: hmm]

5:50 TEttinger: yeah, I just didn't understand why it was slow

5:50 immutable data structures are part

5:50 vector-to-other conversions are slow when done many times

5:51 noncom: it is just that i made some programs with variable geometries (using VBOs) wit clojure + jmonkeyengine 3 and it was rather fine..

5:51 i had to use java arrays though

5:51 or ByteBuffers from nio

5:51 which is ok

5:51 TEttinger: I think the issue was that there's no "easy way" to make clojure fast

5:53 I love how expressive clojure is, but in my experience games can't benefit much from that due to slowdown

5:53 my clojure code was monstrous though

5:53 noncom: how do you think, is it slow on calculations or flow control?

5:53 TEttinger: calculations are mostly java speed

5:54 noncom: i don't know what to think of what you're saying coz i was kinda doing some games with clojure and they were very ok with speed...

5:54 TEttinger: if you have enough type hints you should be fine, and even then, untyped-arithmetic warnings didn't speed yup much

5:54 noncom: but i did not do this kind of game like you did

5:54 TEttinger: it's possible all my problems were logic related

5:54 or libgdx related

5:54 noncom: this worth a further research

5:54 TEttinger: sounds like you used less wrapping

5:55 https://github.com/tommyettinger/Ravager

5:55 noncom: i am not an addict of "make everything functional whatever the cost"

5:56 actually, i have designed and am using a OO system for my apps

5:56 TEttinger: well https://github.com/tommyettinger/Ravager/tree/master/ravager/desktop/src-common/gaunt/ravager is where you want to look

5:56 noncom: this OO things seems very fast

5:56 (comparingly)

5:57 TEttinger: I would guess that libgdx has some slowdown as well relative to a jmonkey bit

5:57 noncom: TEttinger: you have used play-clj, i think this served a huge lag too

5:57 TEttinger: no, actually it got faster on play-clj

5:57 because i wasn't leaking VRA<

5:57 noncom: why do you think libgdx is slower? i was thinking the opposite... it is more low-level than jme

5:57 TEttinger: M

5:58 i dunno. libgdx isn't just an OGL wrapper

5:58 never used JME

5:59 noncom: jme isn't either. it has a whole thick layer between ogl and user so that you do not even see a bit of ogl.. libgdx is different. it is like ogl but with optimisations (as i see it for now)

5:59 so i think that i will devise my thing and we shall see what comes out of it

6:00 TEttinger: you don't see any OGL from libgdx either... the most I had was I called some things to clear the screen from GL

6:00 I need to go to bed

6:00 good luck with your non-functional clojure game lib?

6:01 noncom: ok, good night! i will continue the research. i think that wen i get somewhere, we may run some tests to see what is all this slowdown thing for

6:56 dabbelingClj: Hi there I want to build a clojure web app with absolute minimal UI, what approach and libraries can you suggest?

7:08 No ideas on how to build simple web Uis?

7:08 gyim: dabbelingClj: i would suggest compojure, hiccup and Twitter UI bootstrap

7:08 dabbelingClj: 3 libs

7:08 that "feels" quite heavy

7:08 scape: :sigh

7:09 dabbelingClj: hiccup is templating?

7:10 gyim: clojure web libs usually do one thing well, which is in contrast to providing a big all-in-one framework like rails or django

7:10 clgv: dabbelingClj: no not heavy since the individual libs are small ;)

7:11 dabbelingClj: hiccup is for building html via clojure datastructures. for templating there are other option.

7:12 dabbelingClj: how would the interaction between hiccup and twitter bootstrap look like?

7:13 gyim: hiccup is just for generating html. So you generate a html that uses the elements/attributes bootstrap supports

7:14 dabbelingClj: how does bootstrap compare to clojurescript in regard to build "interactive" web apps?

7:14 clgv: dabbelingClj: apples and oranges ;)

7:15 dabbelingClj: I'd figure its not really a clojure problem

7:15 more that the "web" is messed up

7:16 but I still dont like it

7:16 "web-components"

7:16 clgv: dabbelingClj: you can setup a tiny web ui with ring+compojure+hiccup pretty fast. I did that for a project

7:17 agarman: I liked this demo: http://rigsomelight.com/2014/05/01/interactive-programming-flappy-bird-clojurescript.html

7:17 dabbelingClj: clgv: you have example link?

7:17 clgv: agarman: not nightplay, right?

7:17 agarman: nope

7:17 it uses figwheel

7:18 clgv: dabbelingClj: no, currently closed source. it's going to be open source in some weeks#

7:19 dabbelingClj: but is pretty easy getting started with the READMEs of these projects. but there are already enough blogposts that offer more I guess

7:19 dabbelingClj: clgv: can you suggest "good" blog posts?

7:20 bhauman: agarman: :)

7:20 clgv: dabbelingClj: as I said I used the READMEs only ;)

7:20 dabbelingClj: clgv: yes and how long did it take you?

7:21 clgv: also interesting: how much exposure to javascript/HTML/CSS did you have before

7:22 clgv: dabbelingClj: it doesnt use CSS or javascript - that's what I assumed "tiny web ui" means ;)

7:22 agarman: bhauman: I showed that demo to folks at work. Everyone loved it.

7:22 (inc bhauman)

7:22 lazybot: ⇒ 4

7:22 clgv: dabbelingClj: if I had time I'd add twitter bootstrap

7:23 dabbelingClj: getting up and running with basic stuff and authentication/authorization approx 1-2 hours

7:23 dabbelingClj: clgv: see I dont need that

7:24 I think i misplaced my questions

7:24 gyim: dabbelingClj: how much experience do you have? I think clojure is not so good for learning about basic web technologies (http, html, css, js), but once you are familiar with these, it is very easy to use imho

7:24 clgv: dabbelingClj: yeah I did need authorization since the web ui controls a server program ;)

7:24 dabbelingClj: what clojure librariy can I use for rapid HTML prototyping, possibly with interactive feed back?

7:26 clgv: dabbelingClj: ring+compojure+hiccup

7:28 dabbelingClj: clgv: ok but that would still bee code in editor, go to browser and then hit refresh?

7:28 clgv: I think i'm looking for a more integrated approach , maybe with LT

7:29 clgv: dabbelingClj: well you start a server via ring and can reload the web ui in browser as you like

7:29 dabbelingClj: clgv: something where i see instantly my changes applied

7:29 clgv: dabbelingClj: yeah maybe LT has something like that since it is running in a browser itself

7:29 dabbelingClj: clgv: well i guess i give hiccup a try, but first lunch :)

7:31 bhauman: agarman: thanks man1

7:58 turbopape: Hi guys,

7:58 I want to use storm, but I am afraid that the clojure DSL has not been worked on since at least two years...

7:59 Can I use it with peace of mind, or was its support dropped (the clojure DSL that is ?)

7:59 agarman: I'm not sure the state of storm

7:59 I skipped using it at previous gig, and same at this current

8:00 turbopape: agarman storm as a whole seems to be well, It's for the clojure DSL that I'm worried ...

8:01 And I really am afraid of doing this in java ... :(

8:02 agarman: turbopape: probably better to ask storm folks

8:03 turbopape: indeed agarman, thank you, I just wanted to get a feel how much is it being used by clojurians...

8:03 not that much, as far as I can tell ...

8:03 boyscared: i've used it, but it was about 2 years ago

8:03 in a primarily java app, no less

8:04 it worked fine back then, and i'd probably conclude that there's no reason it wouldn't still work

8:04 turbopape: thanks boyscared , did you use the clojure DSL ?

8:04 boyscared: nope

8:05 turbopape: Have you heard about someone using it boyscared ?

8:06 boyscared: not personally, no. i'd venture you'd be fine, but i can't really speak authoritatively on it

8:06 turbopape: ok boyscared . I'll ask about this on their mailing-list. Thanks ! cc agarman

8:06 boyscared: were i you, i'd probably slap together a quick prototype

8:28 gfredericks: promise->future: https://github.com/fredericksgary/repl-utils/blob/master/src/com/gfredericks/repl/util.clj#L4

8:33 clgv: gfredericks: hehe. do you need that often enough?

8:54 gfredericks: clgv: no just this once

8:54 clgv: it supports the repl-utils library, it is not itself a repl utility I intend to use :)

9:05 trptcolin: any input y’all can give would be super-helpful: https://docs.google.com/forms/d/1ejjQgGkwmP1GLn2lFs5jGIBBQsKC1hc5aVieu1VwmYs/viewform

9:35 bja: any thoughts on why clojure.lang.Reflector.invokeMatchingMethod would be failing on a class at runtime in a jetty handler but not in the repl?

9:36 mpenet: gfredericks: looks a bit like a lightweight lamina result-channel

9:36 I think ztellman has been extracting this kind of stuff to a separate lib

9:37 https://github.com/ztellman/manifold

9:44 myguidingstar_: hi all, is there any tool that helps with producing url to static assets in HTML for Clojure webapps?

9:44 Viesti: Is there an idiomatic way to return a literal value from a function literal?

9:44 justin_smith: bja: is the repl using the same classpath as the jetty handler? is it running jetty via lein ring or something or is it an uberwar servlet?

9:45 AeroNotix: Viesti: (constantly literal)

9:45 TimMc: Viesti: #(do 5) (ew) or (constantly 5)

9:45 justin_smith: myguidingstar_: look at ring.middleware.wrap-resource

9:45 Viesti: Thanks AeroNotix and TimMc

9:46 AeroNotix: nw

9:47 clgv: bja: you probably have reflection warning there in the repl as well. if you add the expected typehint you probably get more information when the error happens in jetty

9:47 justin_smith: it is so appropraite that (partial take 5) is lazy

9:48 Viesti: though those two options still feel a bit funny, but maybe I'm doing it wrong

9:49 justin_smith: there is always (fn [] 5)

9:49 I mean what feels funny about them?

9:50 noncom: constantly is not funny

9:50 Viesti: (into {} (map #(do [(.replaceAll (key %) "\\." "\uFF0E") (val %)]) {"foo." "bar"}))

9:50 could do

9:50 (into {} (for [entry {"foo." "bar"}] [(.replaceAll (key entry) "\\." "\uFF0E") (val entry)]))

9:50 justin_smith: noncom: it is funny that fn [& _] is fewer chars than constantly and gets you the same result

9:50 Viesti: using for

9:51 just realised the list comprehension option

9:51 noncom: justin_smith: this is indeed funny :)

9:51 fizruk: ,(take-while not-empty (map (partial take 2) (iterate (partial drop 2) [1 2 3 4 5])))

9:51 clojurebot: ((1 2) (3 4) (5))

9:51 fizruk: is there a cleaner way to do that? ^

9:51 the actual list is “rest of the arguments"

9:51 justin_smith: (partition-all 2 (range 1 6))

9:51 ,(partition-all 2 (range 1 6))

9:51 clojurebot: ((1 2) (3 4) (5))

9:52 fizruk: justin_smith: great!

9:54 arrdem: 'mornin

9:54 noncom: hi!

10:01 myguidingstar_: justin_smith, sorry for my unclear question

10:03 hi all, is there any tool that helps with *producing url* to static assets in HTML for Clojure webapps? maybe something like: {{git commit's unique id}}+{{path-to-asset}}

10:05 justin_smith: with caribou we have a reverse-routing function called route-for that we use in templates

10:06 though you probably don't want to switch an existing app to caribou, such a function should not be hard to write

10:07 though it is handy for DRY reasons to have a router that also lets you calculate in reverse (the info you provide eg. compojure is sufficient for compojure to generate a reverse routing lookup, though it does not do so)

10:08 I think there are a few routing libs that provide reverse routing (including polaris which we wrote for usage in caribou)

10:11 gfredericks: mpenet: these channel-things don't normally throw exceptions the way futures do, amirite?

10:28 YourRatzon: Hello everyone, I am writing a compiler in clojure and having trouble tokenizing lines. Can someone help?

10:28 gfredericks: YourRatzon: probably so

10:29 YourRatzon: here is my question on SO: http://stackoverflow.com/questions/24060195/tokenizing-a-string-in-clojure?noredirect=1#comment37103057_24060195

10:29 http://stackoverflow.com/questions/24060195/tokenizing-a-string-in-clojure

10:30 still here

10:31 gfredericks: YourRatzon: you could look at how clojure's reader does it (in java): https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/LispReader.java#L444

10:35 mpenet: gfredericks: if you deref a result-channel where an exception occured, it will rethrow

10:35 gfredericks: oh nice

10:35 mpenet: gfredericks: so same thing I think

10:36 gfredericks: unlike core.async

10:36 mpenet: yep, I am annoyed by that too

10:36 see the example here https://github.com/ztellman/manifold#deferreds

10:36 clojurebot: No entiendo

10:36 gfredericks: eh, it's a different model

10:36 mpenet: it is

10:37 YourRatzon: gfredericks: not sure how that helps me...

10:37 mpenet: everything is a value in core.async, no disctinction

10:37 gfredericks: YourRatzon: do you understand what it does?

10:37 mpenet: distinction*

10:37 YourRatzon: scans the string until the strings end

10:37 clgv: gfredericks: slingshot annoys me right now. I just want to catch and rethrow an exception with throw+ to capture context information...

10:38 gfredericks: YourRatzon: you probably don't want to use a regex up front to split things

10:39 YourRatzon: Ok, how should I do it? it's so simple for all the other tokens

10:39 just the string literals causing problems

10:39 borkdude: YourRatzon someone has suggested instaparse, that may be what you ened

10:39 gfredericks: +1 to instaparse

10:39 clgv: huh? is this related to catch-data?

10:40 clgv: gfredericks: I just remembered talking about slingshot with you some other day ;)

10:40 YourRatzon: I see

10:41 gfredericks: clgv: yeah what exactly is slingshot doing for you? what's "context information"?

10:41 YourRatzon: wanted to see if there was a simple line i could add to my regex, guess not..

10:41 clgv: if I need this more often I build a rethrow-context macro ;)

10:41 gfredericks: local binding values are included

10:41 gfredericks: clgv: I think that feature is so weird

10:41 clgv: but only if I throw data and not exceptions :(

10:42 gfredericks: huh? why?

10:42 gfredericks: clgv: because it's only going to be programmatically useful if you start making assumptions about the names of the locals at the throw point

10:43 clgv: gfredericks: I am processing large data and at some point it fails and I currently have no idea where. since it process parallel a println strategy doesnt tell me that much ;)

10:43 gfredericks: I need it for interactive debugging only^^

10:44 gfredericks: clgv: would be interesting to include it as metadata on the ex-info map

10:44 that way it doesn't make its way into logging or anything, but it's there at the repl

10:44 clgv: right

10:45 gfredericks: clgv: so the throwing in this case is by your code or a library?

10:46 clgv: gfredericks: my code. so I could wrap a custom macro around it, that does the job without using slingshot...

10:46 gfredericks: clgv: mpenet just submitted a PR to catch-data with a throw-data macro

10:46 I could add the locals-as-metadata feature; would that solve all your problems?

10:47 clgv: gfredericks: sounds great

10:47 gfredericks: does throw-data offer an option to keep the exception chain intact?

10:47 gfredericks: wat does that mean

10:48 clgv: usually exceptions offer a constructor where you can pass another exception as cause

10:48 gfredericks: oh right; yes

10:48 just like clojure.core/ex-info

10:48 right now the impl is just `(throw (ex-info ~@args))

10:48 I was considering a string-only option as well

10:48 clgv: yes indead

10:49 gfredericks: where you'd get an empty map, but still having locals-as-metadata

10:49 clgv: ah ok. that'll work with the metadata added :D

10:49 gotta star your project to find it, when the change is released ^^

10:49 YourRatzon: ok thank you gfredericks

11:00 clgv: gfredericks: humm according to the source catch-data is not combinable with other catch-declarations in the same "try"?

11:00 err same "try+"

11:01 gfredericks: clgv: comments? https://github.com/fredericksgary/catch-data/pull/3

11:01 clgv: it's not?

11:03 clgv: gfredericks: I did not try it but the macro expands to (try body-forms (catch Throwable t ...) final clause)

11:03 gfredericks: ah do you extract all other to that "cond"?

11:04 gfredericks: prollably

11:04 clgv: ah ok.

11:04 I expected a (catch ExceptionInfo ....) and other catch clauses inserted literally

11:05 gfredericks: I think that's tricksy

11:05 due to edge cases

11:05 clgv: yeah, I dont want to say anything about right and wrong with that. just my expectation when looking at the source ;)

11:06 gfredericks: the main constraint is that you can't have one catch clause inspect the exception and defer to the next one

11:07 once you rethrow you skip all the remaining catches

11:07 so certainly all the catch-data clauses have to be done together

11:07 clgv: gfredericks: are only maps allowed for throw-data? is that a limitation of ex-info?

11:08 gfredericks: I'm sure it's possible to statically determine a more optimal expansion -- I have no idea what the perf implications are

11:08 ,(ex-info "not a map" [])

11:08 clojurebot: #<ClassCastException java.lang.ClassCastException: clojure.lang.PersistentVector cannot be cast to clojure.lang.IPersistentMap>

11:09 clgv: ok.^^ otherwise a check whether metadata can be added to the object would be needed

11:09 deathknight: hiya fellas

11:09 clgv: gfredericks: looks good so far

11:09 deathknight: a lot of firsts right now: Debian, because all of the Clojure tutorials were not on Windows, and now epic5 irc :)

11:11 clgv: deathknight: you can start learning on any plattform where counterclockwise, cursive or lighttable work. since they offer you all you need to get started. later, when you need leiningen - well it's better test on linux and mac os ;)

11:12 *tested

11:12 deathknight: :) Hence I feel I made the right decision by dual bootingh.

11:13 Has anyone made calls to the TeamworkPM API? They have a java example set up - it's a bit over my head at the moment

11:13 Signoff: I'm using emacs live at the moment :]

11:13 err, I mean "clgv:"

11:14 clgv: well you gotta ask someone else for solving emacs problems ;)

11:15 gfredericks: clgv: I think I also want string interpolation a lot of the time

11:15 deathknight: Hah, emacs is treating me right. I'm referring to calling in java libraries and such

11:15 clgv: deathknight: you read about java interop from clojure already?

11:16 gfredericks: clgv: e.g., if there were a throw-data-f that automatically used https://github.com/clojure/core.incubator/blob/master/src/main/clojure/clojure/core/strint.clj#L49 with the map data in scope

11:16 that would be sooper hot

11:16 deathknight: I have not, clgv!

11:16 I'm going through Clojure Programming by O'Reilly at the moment

11:17 gfredericks: then I could (throw-data "Expected a keyword but got ~(pr-str arg)" {:arg x})

11:17 clgv: deathknight: ah ok. then maybe you want to jump to that chapter to get to know as much as you need right now

11:18 deathknight: <3

11:19 deathknight wants to deathhug you for your help

11:19 clgv: gfredericks: I am not a fan of that string interpolation.I am used to just use "format" ;)

11:20 gfredericks: clgv: with format you can't identify the things by name though

11:20 clgv: gfredericks: no but by position

11:20 gfredericks: but a map of data doesn't have positions

11:21 clgv: ,(format "%2$s %1$s" 1 2)

11:21 clojurebot: "2 1"

11:21 clgv: gfredericks: but you dereference that data explicitely in your example?

11:21 ah no. you build the map...

11:21 gfredericks: clgv: no, the map can be implicitly in scope

11:22 clgv: gfredericks: if it causes no unnecessary expensive overhead, there should be no harm to add that feature ;)

11:24 ,(require 'clojure.core.strint)

11:24 clojurebot: #<FileNotFoundException java.io.FileNotFoundException: Could not locate clojure/core/strint__init.class or clojure/core/strint.clj on classpath: >

11:25 clgv: &(require 'clojure.core.strint)

11:25 lazybot: java.io.FileNotFoundException: Could not locate clojure/core/strint__init.class or clojure/core/strint.clj on classpath:

11:25 arrdem: aw man why's Var final...

11:31 technomancy: it's weird how "final" means two completely unrelated things

11:33 gfredericks: can't extend and can't reassign?

11:35 hyPiRion: technomancy: Guess what the keyword "transient" in Java means.

11:36 cbp: ~reactjs

11:36 clojurebot: reactjs is a poorly implemented comonad

11:36 cbp: kek

11:40 irctc: Is there a way using just regex to pull out the number 1311 in brackets (re-find #"\[\d+\]" "Category 123 [1311]")? Right now I get [1311] but I want [ ] to be excluded?

11:41 ToxicFrog: irctc: wrap the \d+ in () and use groups

11:42 mpenet: works with re-find just fine

11:42 ,(re-find #"\[(\d+)\]" "Category 123 [1311]")

11:42 clojurebot: ["[1311]" "1311"]

11:43 irctc: thanks

11:44 borkdude: how do I define a multimethod which I can call like this: (defmulti foo number? [x] "You have given a number") (defmulti foo coll? [x] "You have given a collection")

11:44 mpenet: you prolly want to just dispatch on `type`, but this screams for a protocol

11:45 borkdude: hmhm

11:45 gfredericks: multimethods are pretty good protocols

11:45 I think clojure.core/type is a sneaky-cool function :)

11:45 mpenet: depends on the context (performance)

11:46 cbp: (defmulti foo type)

11:46 technomancy: it's very rare for multimethods to be a performance bottleneck

11:46 borkdude: (type 1) gives me something else than (type 1.0)

11:46 I want to use the same definition based on the output of number?

11:46 gfredericks: borkdude: use Number

11:46 borkdude: multimethods respect inheritance

11:47 hyPiRion: gfredericks: perhaps better to use `instance?` instead of `type`?

11:48 borkdude: ok cool (instance? java.lang.Number 1.0)

11:49 hyPiRion: wait hummm

11:49 gfredericks: hyPiRion: wat?

11:49 cbp: type will work fine

11:50 mpenet: type can be weird:

11:50 gfredericks: I like multimethods + type because you can do tricksy things with metadata

11:50 mpenet: ,(type (with-meta {:a 1} {:type String}))

11:50 clojurebot: java.lang.String

11:50 borkdude: it just works: (defmethod text Number [x]

11:50 "you passed a number")

11:50 cool

11:50 cbp: (defmulti foo type) (defmethod foo Number [x] :number)

11:50 borkdude: I used (defmulti text instance?) btw

11:50 hyPiRion: woah, today I learned something new.

11:51 aka: hyPiRion: that keeps happening to me

11:51 hyPiRion: I just thought it checked for equality

11:51 justin_smith: that's what distinguishes type from class

11:51 borkdude: so type? also works, hmm let me see

11:53 cbp: ,(isa? Long Number)

11:53 clojurebot: true

11:53 gfredericks: hyPiRion: I think it even does inheritance stuff in collections

11:54 ,(defmulti jean (fn [a b] [(type a) (type b)]))

11:54 clojurebot: #'sandbox/jean

11:54 gfredericks: ,(defmethod jean [Number Number] [a b] "haha two numbers")

11:54 clojurebot: #<MultiFn clojure.lang.MultiFn@1093b10>

11:54 gfredericks: ,(jean 3M 4N)

11:54 clojurebot: "haha two numbers"

11:54 gfredericks: ,(defmethod jean [Long Long] [a b] "haha two LONGs")

11:54 clojurebot: #<MultiFn clojure.lang.MultiFn@1093b10>

11:54 gfredericks: ,(jean 3 4.2)

11:54 clojurebot: "haha two numbers"

11:55 gfredericks: ,(jean 3 4)

11:55 clojurebot: "haha two LONGs"

11:55 gfredericks: I have no idea how nested it will get, or if it works with maps or what.

12:00 borkdude: emacs question: is it possible if you put the point on a symbol, the places where the symbol is used get highlighted?

12:00 clgv: ,(use 'clojure.set)

12:00 clojurebot: #<SecurityException java.lang.SecurityException: denied>

12:00 clgv: oh that's new

12:00 technomancy: borkdude: M-x package-install idle-highlight

12:00 clgv: ,(require '[clojure.set :as s])

12:00 clojurebot: nil

12:00 borkdude: technomancy thanks :)

12:00 technomancy: np

12:01 gfredericks: (inc technomancy)

12:01 lazybot: ⇒ 111

12:02 gfredericks: technomancy: where do you enable this? every file everywhere? just "code files" FSVO code?

12:02 clgv: ,(let [types #(-> % type ancestors)] (->> [1 1.0 1M 1N] (map types) (apply s/intersection)))

12:02 clojurebot: #{java.lang.Number java.io.Serializable java.lang.Object}

12:02 technomancy: gfredericks: (add-hook 'prog-mode-hook 'idle-highlight-mode) is my recommendation

12:02 gfredericks: technomancy: wat is prog-mode

12:03 technomancy: it's for progging

12:03 justin_smith: I think it is a parent mode that language modes inherit

12:03 borkdude: :-D

12:03 gfredericks: (inc prog-mode)

12:03 lazybot: ⇒ 1

12:03 borkdude: gtg, thanks guys

12:03 justin_smith: http://emacsredux.com/blog/2013/04/05/prog-mode-the-parent-of-all-programming-modes/

12:04 "the parent of all programming modes"

12:05 hyPiRion: gfredericks: neat, you learned me something new today

12:05 arrdem: theoretically

12:09 gfredericks: hyPiRion: I think clojure has a few interesting features that get mostly ignored

12:12 bbloom_: clojurebot: forget reactjs

12:12 clojurebot: Excuse me?

12:13 bbloom_: ~forget reactjs

12:13 clojurebot: It's greek to me.

12:13 bbloom_: *shrug*

12:13 amalloy: gfredericks, hyPiRion: not collections in general, but vectors specifically i think

12:13 bbloom_: you have to tell him what to forget about it

12:13 bbloom_: ~reactjs

12:13 clojurebot: reactjs is a poorly implemented comonad

12:13 bbloom_: clojurebot: forget reactjs is a poorly implemented comonad

12:13 clojurebot: 'Sea, mhuise.

12:14 amalloy: now *that* will just make it worse. you taught him about "forget reactjs"

12:14 stand back, bbloom_, and let a pro do it

12:14 gfredericks: amalloy: and just shallow occurrences?

12:14 bbloom_: amalloy: LOL

12:14 i suck

12:14 amalloy: clojurebot: forget forget reactjs |is| a poorly implemented comonad

12:14 clojurebot: I forgot that forget reactjs is a poorly implemented comonad

12:14 amalloy: clojurebot: forget reactjs |is| a poorly implemented comonad

12:14 clojurebot: I forgot that reactjs is a poorly implemented comonad

12:14 amalloy: gfredericks: i don't understand what that means

12:14 bbloom_: amalloy: much thanks

12:15 gfredericks: amalloy: [C1 C2 C3] vs [C1 [C2 C3]]

12:15 bbloom_: now that he who shall not be named has gone, we can purge his nonsense from the brain of poor sweet clojurebot

12:15 tbaldridge: bbloom_: I have still to understand why I would want to know that something is a co-monad

12:15 bbloom_: tbaldridge: you wouldn't :-P

12:15 amalloy: gfredericks: see https://www.refheap.com/9b7060a5c29c0f80b43bbb598 - vectors cause recursion in isa?, so you can nest them arbitrarily

12:15 gfredericks: clojurebot: <X> is a poorly implemented <sufficiently abstract concept>

12:15 clojurebot: 'Sea, mhuise.

12:16 bbloom_: tbaldridge: i'm trying to rescue reiddraper but i think jimduey may be too far gone ;-)

12:16 justin_smith: "this thing, I don't know what to call it but it reminds me of reactjs in its structure (though it is better implemented)"

12:16 tbaldridge: bbloom_: lol

12:16 gfredericks: amalloy: nice

12:16 bbloom_: I think test.check has at least three different monads

12:16 tbaldridge: it does seem that once people go down the monad trail they stop producing practical code

12:16 * tbaldridge biased

12:17 reiddraper: really?

12:17 bbloom_: tbaldridge: ah c'mon now

12:17 amalloy: sshhh, tbaldridge is biased, don't listen to him

12:17 bbloom_: tbaldridge: you went down the trail and returned from the depths

12:17 you built something practical with monads

12:17 tbaldridge: bbloom_: very little, lol

12:18 gfredericks: tbaldridge: also test.check with its three monads has been very practical for me

12:18 reiddraper: i think test.check is practical.

12:18 and their use is basically 100% transparent to the user

12:18 bbloom_: and at least reiddraper had a good excuse for test.check, non-determinism and backtracking are actually a sensible use case

12:18 tbaldridge: I've since repented of my ways, infact a prototype of the go macro I'm working on is based on mutable data structures, it cuts the code size by about 1/2

12:18 bbloom_: although i'd have used a state machine transducing over a sequence, but that's jsut me :-P

12:18 gfredericks: it's also worth mentioning that despite the three monads, reiddraper didn't try to twist clojure into having some sort of generic monad construct

12:18 hyPiRion: gfredericks: yet

12:18 reiddraper: hyPiRion: lol

12:19 bbloom_: as far as i'm concerned, there are two useful monads: the list monad (we've got that!) and the continuation monad (i'm putting it in to eclj :-P)

12:20 amalloy: aw, it's cheating to count continuations as one monad, and then use it to model exceptions and io

12:20 (which i recall, perhaps incorrectly, is your plan)

12:20 bbloom_: amalloy: i didn't say i was going to include do notation or even expose the monadic protocol

12:20 simply that all this busienss about "free monads" is about creating interpreters

12:20 amalloy: i know you aren't. you hate generic monads and functors

12:20 tbaldridge: reiddraper: just out of curiosity does test.check need monads? I'm wondering since I've found that most/all of mukanren can be implemented via lazy seqs instead of monads

12:21 bbloom_: if you have an extensible interpreter that can (critically important!) grow as well as restrict it's set of functionality, then you don't do syntax

12:21 reiddraper: tbaldridge: suppose it depends on how you define "need"

12:21 tbaldridge: or plerhaps once I start using mapcat + lazy seqs I'm technically using monads anyways,

12:21 gfredericks: tbaldridge: bbloom_: I think the most syntactically helpful thing I've done while using it is a variant of clojure.core/for, which works since the generators are monadic

12:22 hiredman: gfredericks: speaking of test.checks for, it doesn't seem to work just like clojure's, it didn't seem to let me refer to values from "outer" generators in "inner" generators

12:23 gfredericks: hiredman: that sounds wrong?

12:23 bbloom_: tbaldridge: yeah, you'd technically be using monads.... but i argue it's like technically using a turing machine

12:23 gfredericks: hiredman: the basic case with multiple clauses turns into bind

12:23 bbloom_: tbaldridge: nobody wants to program a turing machine

12:23 tbaldridge: as to my comment awhile back about "practical code", what I meant was that there is so much dense theory involved in monads, free monads, co monads, etc. That people can spend years reading up on the stuff instead of producing code.

12:23 gfredericks: hiredman: so the outer value should be visible everywhere below

12:23 hiredman: gfredericks: ok, I'll try again(and harder) some time

12:23 reiddraper: tbaldridge: using monads was a really natural way for me to write it, and I think it lead to a clean external API, with little "magic" and gotchas

12:23 gfredericks: hiredman: if that's not the case, it's a bug

12:24 reiddraper: tbaldridge: whether you could achieve that or not without them, I'd have to reflect on that a bit

12:24 bbloom_: reiddraper: i'm actually with you that you made the right *practical* call to use monads if that made sense to you there

12:24 gfredericks: hiredman: e.g., this test passes: https://github.com/fredericksgary/test.chuck/blob/master/test/com/gfredericks/test/chuck/generators_test.clj#L20

12:24 arrdem: tbaldridge: by that argument the months I spent reading into lisps and functional languages rather than hacking more C were a waste.

12:24 bbloom_: reiddraper: but you really should consider reifying the internal state in to a map and then reducing over a command sequence

12:25 reiddraper: you'll get all the same properties, plus much better debuggability

12:25 you could pretty easily invent some kind of 'for' syntax for extracting intermediate answers from the state machine too, if you need several monads to cooperate

12:25 gfredericks: reiddraper: we just need one more monad -- the state monad :D

12:25 reiddraper: bbloom_: interesting, i'll definitely consider that

12:29 YourRatzon: Hello, I have a question

12:30 can someone explain the following:

12:30 reiddraper: tbaldridge: to offer another perspective, many of the people who I admire most who're into that theory, produce insane amounts of practical code

12:30 YourRatzon: (filter empty [:s "" [:k "hi"]])

12:30 ([:k "hi"])

12:30 (filter empty [:s "" [:k "hi"]])

12:30 ([:k "hi"])

12:30 (filter empty [:s "" [:k "hi"]])

12:30 ([:k "hi"])

12:30 (filter empty [:s "" [:k "hi"]])

12:30 ([:k "hi"])

12:30 (filter empty [:s "" [:k "hi"]])

12:30 ([:k "hi"])

12:30 (filter empty [:s "" [:k "hi"]])

12:30 oops sorry for multiple lines

12:30 amalloy: ~paste

12:30 clojurebot: paste is not gist.github.com

12:30 amalloy: ~refheap

12:30 clojurebot: https://www.refheap.com/

12:31 gfredericks: ,(empty :s)

12:31 amalloy: YourRatzon: anyway, you're confusing empty? with empty

12:31 clojurebot: nil

12:31 gfredericks: ,(empty? :s)

12:31 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Keyword>

12:31 gfredericks: weird

12:31 YourRatzon: I know, empty is what causes a coll to become empty

12:31 so I don't understand the output

12:32 amalloy: filter is not map

12:33 tbaldridge: YourRatzon: so everything that is not a collection is returning nil and is removed by filter

12:33 reiddraper: amalloy: what's wrong with gist.github?

12:33 tbaldridge: leaving only [:k "hi"]

12:33 amalloy: reiddraper: nothing. it's just clojurebot's stupid inference engine

12:33 and the increasingly absurd things people teach him in order to have fun with said engine

12:33 reiddraper: ah i see, ha

12:34 YourRatzon: tbaldridge: is this intended behavior when filter is ran with a non-predicate, or a bug?

12:34 tbaldridge: YourRatzon: no, there's nothing wrong with using a non-predicate, filter just removes items where (not (pred value))

12:35 YourRatzon: your example is just a bit odd since I can't think of a reason why you would want to do what you're doing, but hey it could work

12:35 ,(filter {:a :b :c :d} [:a :b :c :d])

12:35 clojurebot: (:a :c)

12:36 YourRatzon: tbaldridge: well actually I have a vector full of collections and non-collections and I want to only keep the collections

12:36 gill_: try map?

12:36 tbaldridge: YourRatzon: you could try this then

12:37 ,(filter coll? [:a "foo" 1 [1 2 3] #{1 2}])

12:37 clojurebot: ([1 2 3] #{1 2})

12:37 YourRatzon: thanks that works

12:38 i just came across the (filter empty) behavior by accident and didnt udnerstand why it was working the way it did

12:38 thanks for the explanation

12:38 catern: I just went through https://devcenter.heroku.com/articles/clojure-web-application and I am a little confused - how am I supposed to debug things?

12:38 when I stick print statements in my functions, they don't print to the REPL

12:38 should I print to the web page? /new to web development

12:39 i think i would prefer it if I could print to the REPL..

12:39 (Cider specifically)

12:41 {blake}: In working with this code https://www.refheap.com/61d3a3c7f691c1f26c8084770 amalloy volunteered yesterday (thanks to all for the feedback, btw) I realized that it gives me a list of maps containing vector keys and vector values, when I really want one map.

12:41 So I changed the "(conj (index content tt) {tt content})" to "(assoc (index2 content tt) tt content)" figuring that would get me the right structure, even though multiple entries for a key would wipe each other out. Instead, I get a "clojure.lang.LazySeq cannot be cast to clojure.lang.Associative".

12:41 nullptr: catern: they print to the browser debug console

12:42 catern: nullptr: whaaaaaaaaat really? just auto[magically?

12:42 (by print to the web page I meant just stick in calls to "str" in random places)

12:42 (and inject that into the hmtl)

12:43 automagically*

12:43 i don't see them in "Console" in Firefox's debugger, where should I be looking?

12:43 nullptr: str just makes a string -- but assuming you're using print and have enabled it[1] the messages should show up there 1. https://github.com/swannodette/om/blob/master/examples/counters/src/core.cljs#L7

12:44 catern: no no, haha

12:44 i'm just using clojure and compojure and ring

12:44 to serve static HTML

12:45 nullptr: i see, assumed cljs from your commentary

12:45 catern: and if I put a (println "Foobar") in the function that produces my index page, it doesn't seem to print anywhere

12:45 it sure would be cool if that somehow ended up in the browser debug console :D

12:46 amalloy: {blake}: a for-comprehension necessarily produces a sequence, and doesn't have access to "previous" values. but it should be possible to do what you want either by reducing over something, or using an `(into {} (for ...))` stanza once you're done producing the list

12:47 {blake}: amalloy, So the error itself is because it IS a lazy sequence, even though I'm realizing it right then?

12:48 amalloy, (I mean, I figured I could do it that way, but I'm not always sure that the way I'm thinking is idiomatic.)

12:49 amalloy: it has nothing to do with laziness or realizing. sequences just aren't maps. i don't know what (index2 content tt) returns, but apparently it's a sequence, and you're trying to assoc onto it

12:49 even if it worked, you'd still get out a sequence in the end, because that's what for produces

12:50 {blake}: index = index2, I just renamed it to work on it.

12:50 The idea was to make it return a map rather than a sequence.

12:52 But it can't return a map because it's a "for"...that's what I'm missing.

12:56 gill_: {blake}: what data do you pass in? have a paste of that?

12:57 devn: technomancy: any idea of how I can get rid of this error: java.io.FileNotFoundException: data/stats/all.edn (No such file or directory) -- this is after loading the test data for clojars.org

12:57 and trying to view a specific project page, like 'clojure-useful' or whatever

12:58 {blake}: gill_, I'm using https://www.refheap.com/86314 for sample data.

12:59 devn: technomancy: nevermind (for now) -- looks like we just need to run the tests

13:01 {blake}: So an "into {}" gives me the right structure, I just have to keep it from overwriting the existing value (which reminds me of a 4clojure exercise...)

13:03 gill_: so you could call with (into {} (index sample0 [])) ?

13:04 {blake}: Well, that still overwrites the keys.

13:05 gill_: okay just making sure i understood

13:05 nullptr: bx

13:05 rasmusto: hrm, you're talking about overwriting keys in an (into {}) call?

13:06 {blake}: Right now I have a map of {[vector-key][]...} and I need a map of {[vector-key][value value value]}.

13:06 rasmusto, yes

13:06 rasmusto: i wonder if you could use some combination of partition[-by] and merge-with

13:06 or just a plain old reduce

13:07 amalloy: (apply merge-with into the-maps)

13:08 {blake}: sorcery!

13:08 amalloy: but you need to be careful, {blake}. if you make `index` return a map, then its recursive calls to itself, which expect a sequence, will break! you instead probably want some function wrapping index, which converts the produced sequence into a map

13:10 {blake}: amalloy, Yeah. I've done that. =P

13:18 dbasch: someone needs to restart the process that logs this channel! http://clojure-log.n01se.net/

13:18 or I could host my own on my trusty aws micro

13:20 cbp: dbasch: lazybot also logs logs.lazybot.org

13:20 rasmusto: loglazyloglazy

13:21 dbasch: cool, I was already thinking about writing a logger with some evil replacement patterns

13:21 e.g. filter -> purify

13:21 cbp: monad -> burrito

13:22 dbasch: I like your thinking cbp

13:26 I’m hungry, let’s get a monad

13:27 arrdem: what? it's not 12:00UGT yet!

13:27 gfredericks: there was a group that went out for monads at clojure/west one day

13:32 behelit: planning to take clojure for a spin. figured i'd start with a web project. which framework(s) are worth looking into?

13:33 nDuff: behelit, in general, we don't like frameworks here. :)

13:33 deathknight: Hey guys, using java for my first time with lein and cider-jack-in can't start a REPL server.

13:33 behelit: coming from python+django (form heavy, crud apps) and erlang+cowboy (webapps, ws etc).

13:33 technomancy:

13:33 nDuff: behelit, ...the Clojure Way encourages small tools that aren't heavily opinionated about how they're used or combined with others.

13:33 cbp: behelit: Luminus is gr8

13:33 behelit: nDuff: ok, hat lbs for form generation, validation, session management, dbdrivers etc?

13:34 heh, s/hat lbs/what libs/

13:34 :)

13:34 rasmusto: heh, s/hat

13:35 behelit: and routing of course.

13:35 arrdem: -f /dev/hat

13:35 nDuff: ...now, if you wanted something that _was_ very framework-y, there's Hoplon (hoplon.io)

13:36 technomancy: compojure is what everyone uses for routing. there are about a bajillion validation libraries that seem to all do the same thing though.

13:37 cbp: I don't use compojure!!

13:37 nDuff: ...in terms of database drivers, there's clojure.java.jdbc, which everything backends into, and then a few different flavors on top

13:37 technomancy: ~guards

13:37 clojurebot: SEIZE HIM!

13:37 behelit: hehe

13:37 cbp: Nooo! death to macros

13:37 behelit: and templating?

13:38 ring for middleware it seems

13:38 technomancy: behelit: templating depends on who's going to be writing them. if it's all going to be handled by clojure programmers then hiccup is definitely the simplest choice.

13:38 but it's not so good for interacting with designers

13:38 nDuff: behelit, ...so, the shiny new way to do things is to have your UI generated client-side with Om, which is bloody awesome (and has a hiccup-like interface).

13:38 cbp: behelit: http://www.luminusweb.net/

13:38 technomancy: please don't generate your HTML exclusively client-side =(

13:38 nDuff: behelit, ...but that's if you're writing something that's a single-page-app everything-rendered-clientside type deal.

13:38 behelit: cpetzold: checking that out.

13:39 cbp: (inc cpetzold)

13:39 lazybot: ⇒ 1

13:39 justin_smith: technomancy: you crufty old gnu-hippies who never turn on javascript will have to crack one of these days

13:39 behelit: nDuff: yeah, we've used react, angular et al for webapps previously. Will look into Om.

13:39 koreth_: Search engines also don't deal well with client-side page generation (though Google is improving in that area recently). Not an issue if your site isn't public, of course.

13:39 arrdem: justin_smith: I'll just keep waiting until we replace JS with a real language...

13:39 nDuff: behelit, ...also, the "death to macros" advice given by cbp should be taken into account when deciding on database libraries; Korma is much, much too macro-centric in my experience; makes it hard to work with sometimes.

13:40 behelit, *nod* -- if you're familiar with React, you'll be very very comfortable with Om.

13:40 technomancy: justin_smith: maybe once they figure out a way to make JS not completely suck from the keyboard

13:40 cbp: Also timbre

13:40 behelit: great stuff

13:40 cbp: so i herd u like macros

13:40 rasmusto: wait, is that possible?

13:41 michaniskin: i love macros

13:41 rasmusto: macro macros

13:41 i mean

13:41 cbp: i have a macro inside your defmacro inside your defmacro

13:41 justin_smith: rasmusto: maybe like using m4 and a configure script to generate your clojure macros?

13:41 arrdem: yo dawg i heard u leik macros...

13:41 behelit: nDuff: any db in particular that's commonly used in the community? i currently use postgres, riak, and/or redis in most projects.

13:41 rasmusto: ic

13:42 cbp: behelit: I guess datomic

13:42 behelit: oh. never did try datomic.

13:42 amalloy: arrdem: http://ro-che.info/ccc/20

13:43 cbp: no reason not to use any of the others though but I heard edn support in non clojure languages is kinda bad

13:43 justin_smith: cbp is very much a clojure niche thing, but I don't know how prevalent it is

13:43 behelit: cbp: edn support?

13:43 justin_smith: *it is

13:43 clojurebot: It's greek to me.

13:43 justin_smith: ~edn

13:43 clojurebot: Titim gan éirí ort.

13:43 justin_smith: behelit: edn is a spec describing the most simple level of clojure data literals

13:43 cbp: behelit: like json for clojure

13:44 behelit: ah

13:44 arrdem: amalloy: heh

13:44 cbp: which is what datomic works with

13:44 cpetzold: cbp: lazybot thinks i’m a 0 :(

13:44 behelit: great. i think i have all i need to get started.

13:45 thanks a million, guys

13:46 Jaood: is there a favourite db for datomic?

13:46 storage option

13:48 gfredericks: depends on what you need for perf/scalability and how easy it is for you to setup things

13:48 behelit: oh, datomic can run on top of riak?

13:50 Jaood: gfredericks: was wondering is there is one storage option that is more tested and more well supported than the others

13:50 behelit: yes

13:51 gfredericks: Jaood: not that I know of

13:55 stompyj: catern: heroku logs --tail

13:55 ahhhh

13:55 catern: stompyj: wat?

13:56 stompyj: catern: were you asking about seeing output from your heroku instance locally?

13:58 catern: stompyj: no, I want to see things I print in the REPL

13:58 I don't use Heroku

13:58 things I print in functions that are executed by jetty*

13:58 stompyj: aha, I assumed you did when you linked a URL from heroku

13:59 sorry bout that

13:59 sandbags0: I've added :jvm-opts ["-XX:-OmitStackTraceInFastThrow"] to my project.clj to avoid getting "NullPointerException [trace missing]" errors and now I get a trace, but only the first line of the trace

13:59 clojurebot: Cool story bro.

14:00 sandbags0: anyone know how to get the full trace?

14:00 justin_smith: catern: probably something like /var/log/jetty[N]/*

14:00 cbp: clojurebot: be nice

14:00 clojurebot: No entiendo

14:00 justin_smith: where N if present would be the version

14:00 sandbags0: unfortunately finding out it's in Numbers.java isn't as helpful as it could be

14:01 cbp: maybe its something like ##(+ 1 nil)

14:01 lazybot: java.lang.NullPointerException

14:01 cbp: :-P

14:01 dbasch: catern: are you using cider?

14:02 cbp: sandbags0: you can try using tools.trace

14:02 amalloy: sandbags0: i think tieredstopatlevel can help? the problem is often that the code has been JITed to death

14:02 sandbags0: cbp: thanks, i will look into that

14:02 amalloy: is AOT related here? compojure seems to turn it on by default ":aot :all" maybe i should turn it off?

14:03 i'm not sure if the AOT thing is removing info that the runtime might later want to use

14:03 amalloy: probably not, although i hate aot all

14:03 sandbags0: tyring it without

14:03 behelit: quick question, trying to persuade a colleague to join me: three reasons to use clojure.

14:03 arrdem: if the JIT is killing printlns or :aot :all is disabling code, there are huge correctness issues.

14:03 neither of those compiler steps should do either of those things.

14:04 sandbags0: yep, removing aot didn't help things

14:04 technomancy: arrdem: it's a bug within hotspot

14:04 arrdem: technomancy: heaven help us all...\

14:04 sandbags0: okay so tools.trace looks useful (something like spy/p) but means i have to instrument all my code to figure out where the NPE Is being raised

14:04 * arrdem searches for a cave to take up residence in

14:04 catern: dbasch: yes

14:05 dbasch: catern: check the *nrepl-server* buffer

14:05 catern: dbasch: thaaaaaaaaaank you

14:05 sandbags0: i'm struggling to understand how all the stack information is being lost bar the deepest point

14:06 justin_smith: sandbags0: JIT scrambles the call stack as it optimizes (or at least *can* do so)

14:07 sandbags0: hrmm... okay yes, thanks, that makes sense.

14:07 so i guess my next step is turning off the jit compiler

14:08 arrdem: AFAIK the JVM requires that stack trace frames be reported in JVM model order no mater what the runtime does to optimize code, failure to do so being a major JVM bug. More likely lazy sequence evaluation makes the stack appear out of order.

14:08 s/being/is a/g

14:09 sandbags0: hrmm... seems -Xnojit is no longer with us

14:11 so i found something suggesting -Djava.compiler=NONE will turn off the JIT compiler, not sure how up to date that is

14:12 but i'm still getting "NullPointerException clojure.lang.Numbers.ops (Numbers.java:961)"

14:12 starting to think binary searching with spy/p might have been quicker!

14:12 i struggle with the notion that Clojure can't actually deliver a useful stack trace in the REPL

14:15 dbasch: sandbags0: maybe you’re inc’ing nil or something like that? http://java.dzone.com/articles/reading-clojure-stacktraces

14:15 ,(inc nil)

14:15 clojurebot: #<NullPointerException java.lang.NullPointerException>

14:15 arrdem: ,(doc fnin)

14:15 clojurebot: Gabh mo leithscéal?

14:15 sandbags0: dbasch: yes, i could be doing anything

14:15 dbasch: &(inc nil)

14:15 lazybot: java.lang.NullPointerException

14:15 arrdem: ,(doc fnil)

14:15 clojurebot: "([f x] [f x y] [f x y z]); Takes a function f, and returns a function that calls f, replacing a nil first argument to f with the supplied value x. Higher arity versions can replace arguments in the second and third positions (y, z). Note that the function f can take any number of arguments, not just the one(s) being nil-patched."

14:15 j0ni: dbasch: so i have tried this in my project.clj: [capacitor "0.2.2" :exclusions [org.clojure/core.async]]

14:15 sandbags0: the point is, without some implicated *clojure* code I am left to analyse my entire code path

14:15 j0ni: it doesn't work though - did i do it right?

14:16 arrdem: sandbags0: er... or you could paste a stacktrace and get some help.

14:16 sandbags0: arrdem: i pasted it above

14:16 Numbers.java:961

14:16 that's the entire output in the REPL

14:16 AWizzArd: I would like to combine two leiningen calls: 1. lein jar 2. lein localrepo install target/foo-0.1.0.jar tld.expamle/foo 0.1.0

14:16 dbasch: j0ni: looks right to me, but you may want to ask someone who’s more familiar with how lein deals with dependencies

14:17 AWizzArd: Can this be done with actually calling Leiningen just a single time, and let the same jvm do both jobs?

14:17 arrdem: sandbags0: that single line is worthless. paste (or just read) the whole thing. If that's all the trace that you're getting printed, try (clojure.stacktrace/print-stacktrace *e) at the repl after you replicate the exception.

14:18 gfredericks: AWizzArd: `lein do` can combine commands

14:18 arrdem: *e is a dynamic variable that the last top level exception gets bound to.

14:18 j0ni: dbasch: thanks, i guess that would be technomancy

14:18 sandbags0: arrdem: yep that's all i got, i'll try your trick, thanks

14:18 AWizzArd: gfredericks: will try that, thanks

14:19 technomancy: j0ni: without any context, that looks right to me

14:19 sandbags0: arrdem: marvellous! thank you

14:20 aphyr: What's the right way to establish a binding thread context in a future?

14:20 ,(future (eval '(do (ns foo) (prn *ns*))))

14:20 clojurebot: #<SecurityException java.lang.SecurityException: no threads please>

14:20 sandbags0: i've no idea why the REPL is hiding everything but the top line but that gives me the full-trace, thanks

14:20 arrdem: sandbags0: sane defaults or something, the presumption being that you know how to get the whole thing.

14:20 justin_smith: sandbags0: OK after the error, try (clojure.repl/pst)

14:21 AWizzArd: gfredericks: works well, thanks for the tip.

14:21 sandbags0: justin_smith: better yet!

14:21 justin_smith: it could be you don't have full stack traces turned on (and thus you would have to ask for them)

14:21 sandbags0: ah, i didn't realise this was something one would need to turn on

14:21 perhaps for those who are telepathic with the machine a stack trace is unnecessary ;-)

14:21 justin_smith: usually nrepl will (use 'clojure.repl) such that (pst) suffices

14:22 sandbags0: justin_smith: yep, that does work

14:25 i am now wishing i hadn't lifted prismatic/schema out of this code :)

14:25 arrdem: sandbags0: type signatures, type checking assertions and core.typed are all pretty nice ;P

14:27 technomancy: sandbags0: it's super annoying that you don't get stack traces, and I would like to fix it in a future version

14:27 arrdem: technomancy: sometimes I get a popup stack trace buffer. sometimes. which is more annoying than all the time.

14:28 technomancy: arrdem: in cider you mean?

14:28 arrdem: yarp

14:28 technomancy: I was thinking of reply

14:28 sandbags0: technomancy: now that i know the (pst) trick it's not so bad, but it's a bit startling to be told (as it seemed) "There was an error somewhere fucknutz, take your best shot as to where"

14:28 certainly at a REPL

14:28 technomancy: sandbags0: nah the pst trick is kinda crap

14:28 since you have to re-use every time you change namespaces

14:28 hell of tedious

14:28 sandbags0: O_o

14:29 do Rich & co just write perfect code first time often enough that error handling isn't an issue?

14:30 technomancy: oh man do not get me started on the core team's ideas about usability

14:30 gfredericks: technomancy: that's more due to the problem of having util stuff across namespaces at all

14:30 arrdem: technomancy: I just read the namespace/var code.. you were right about strictly non-hierarchical. I was kinda surprised.

14:30 sandbags0: heh... sorry... won't poke the bear :)

14:30 technomancy: can basically be summed up with "usability is hard, so why bother trying?"

14:30 gfredericks: that's why you need nrepl-discover

14:30 * sandbags0 sighs

14:30 dbasch: technomancy: it’s surprisng how many hard-core tech people think that way, including the bitcoin team and the old linux devs

14:30 gfredericks: technomancy: oh man do not get me started on the leiningen team's ideas about doing things

14:31 they always involve writing emacs libraries

14:31 technomancy: sandbags0: context: https://github.com/technomancy/leiningen/issues/799

14:31 arrdem: (inc gfredericks)

14:31 lazybot: ⇒ 66

14:31 sandbags0: well i guess this is always a problem when you have a "core team"

14:31 they'll have the shit they care about and everything else tends to wither

14:31 trptcolin: aphyr: (future-call (bound-fn [] #(do (ns foo) (prn *ns*)))) is one way to do it iiuc

14:31 technomancy: gfredericks: vim libraries too, yo

14:31 sandbags0: at least it's a Lisp so you can work around it somewhat

14:31 technomancy: ta

14:31 gfredericks: sandbags0: yeah that

14:32 technomancy: sandbags0: y'know, if you get a commit into lein, you get a free sticker

14:32 just sayin'

14:32 sandbags0: technomancy: is there any qwality control operating around accepting commits?

14:33 technomancy: sandbags0: well if you fix #799 I'll make it three stickers

14:33 sandbags0: i look forward to claiming my stickers in 2029 or thereabouts

14:33 i'm still pretty much a clojure new bug

14:34 amalloy: sandbags0: i can confirm that there is not: https://github.com/technomancy/leiningen/pull/688

14:34 technomancy: amalloy: good times!

14:34 sandbags0: heh

14:34 amalloy: (that was a joke pull request i sent, which was insta-merged)

14:34 USAGE: lein repeat 5 do deps, clean, compile, uberjar

14:34 sandbags0: technomancy: that discussion ended in May 2013

14:35 given the circs today i guess that's not encouraging

14:36 technomancy: sandbags0: well, lein is pretty stable; there hasn't been all that much going on since then

14:37 sandbags0: and it's not surprising that a fix that involves two external libs would take longer to address than something that's solely in lein

14:37 sandbags0: i didn't so much mean it as a failure of lein

14:37 which i perceive it isn't

14:37 as... people talking about this in May 2013, still a problem in June 2014

14:37 aphyr: trptcolin: good call

14:38 sandbags0: suggestive of still being a problem come July 2015

14:39 technomancy: not if you fix it =D

14:39 sandbags0: ha, i might understand it come July 2015

14:42 arrdem: technomancy: pardon my poking, but are there specific usability concerns you do have with the core? just curious.

14:43 * technomancy gestures to his entire body of oss clojure work

14:45 weavejester: Out of curiosity, what core?

14:50 mdrogalis: Is it that time of the week again to complain about Clojure's error messages?

14:50 Sorry I'm late!

14:50 arrdem: mdrogalis: sandbags0 started it

14:51 sandbags0: no no i think the core team started it :-P

14:52 technomancy: ~gentlemen

14:52 clojurebot: You can't fight in here. This is the war room.

14:52 sandbags0: ha

14:52 mdrogalis: Hahah

14:53 weavejester: Has anyone heard of a construct like multimethods, but one that merges matching results, rather than returning just one

14:53 mdrogalis: That's an interesting idea.

14:53 weavejester: i.e. multimethods will return the most specific match

14:54 but what if you had something that merged the results via a custom function

14:54 technomancy: sandbags0: anyway, it looks like this works in the current lein release: :repl-options {:caught clojure.repl/pst}

14:54 weavejester: Like ‘some’

14:54 tbaldridge: sandbags0: I think it's worth pointing out that the "core team" differs drastically in what they use. Some emacs, some use nrepl many don't, etc. But none of that is maintained by "the core".

14:55 technomancy: is there anything stopping lein/nrepl from having a different default for stacktraces?

14:55 technomancy: nope, literally working on it right now

14:56 my comments were more about the contents of the stack traces

14:56 tbaldridge: sandbags0: and if you want to go completely off the deep end, you can use stuff like this: https://github.com/AvisoNovate/pretty :-)

14:57 mdrogalis: So I actually use that lib, and it's kind of awesome sometimes.

14:57 arrdem: tbaldridge: ooh nice

14:58 weavejester: I guess what I’m looking for is a more general form of polymorphism…

14:58 technomancy: and the documentation

14:59 mdrogalis: weavejester: Sort of more general, but also more specific in the sense that results have to be associative.

14:59 weavejester: side-effect order would also be another constraint.

14:59 tbaldridge: weavejester: yeah, I've seen a need for that, where the match value is a pattern, and the multi method runs all matches

15:00 weavejester: mdrogalis: Yeah, the order would matter, but it sometimes does with multimethods as well. Hence prefer-method

15:00 tbaldridge: multimethods aren't that complex, should be possible to write something like this. It'd basically be O(n) though

15:00 sandbags0: technomancy: nice!

15:01 mdrogalis: weavejester: That's a good point.

15:01 weavejester: tbaldridge: Yes, though I don’t think it would necessarily be O(n). You’d just need to run it through the ancestors of the dispatch value.

15:01 technomancy: sandbags0: unfortunately getting it in by default has some issues around messing with *1 and friends

15:01 so I think the best we can do is make it easy to enable

15:01 weavejester: So you take the ancestors of each dispatch value, run the function for each one, and then apply a combining function.

15:01 For multimethods this would just be the most specific dispatch.

15:02 tbaldridge: weavejester: ah! I see. If the multimethod has ASeq, ISeq and Cons you wan't all three to run, but not IPersistentVector.

15:02 *want

15:02 weavejester: But you could have “every?” for predicates, so you could add new rules that would narrow the focus

15:04 tbaldridge: Well, consider a keyword like ::natural, that derives from ::integer and ::positive. You’d want both ::integer and ::positive to run, and then their results combined together with “and”

15:04 tbaldridge: right

15:04 weavejester: With a multimethod, you choose one. But if we add a combine function, we can extend functionality without overriding existing rules

15:04 tbaldridge: OOP FTW!!!

15:05 clojurebot: OOP

15:05 clojurebot: Cool story bro.

15:05 weavejester: Haha :)

15:05 tbaldridge: that's basically what you're asking for, super(foo)

15:05 weavejester: Yeah, kinda. But in OOP you manually add the super

15:06 return super(x) && pos?(x)

15:06 So each class is responsible for combining the result

15:06 clojurebot: Roger.

15:09 weavejester: I guess I’m wondering if this multi-multimethod idea has been done in another language

15:10 If just so I can get a better name for it ;)

15:12 bbloom_: weavejester: sorry, i'm a bit late to the chat, but i think i can help

15:12 weavejester: bbloom_: I welcome any help :)

15:12 bbloom_: you're saying you have some dispatch and want to return all possible matches

15:12 yes?

15:12 clojurebot: yes isn't is

15:12 bbloom_: do you need to *execute* all possible matches?

15:12 and in any particular order?

15:14 * bbloom_ reads more closely.... ah you want a "combining fucntion"

15:14 weavejester: Hm, in the simplest case, yes. In theory there are ways of discarding a result based on the dispatch vaue

15:14 Yes, so consider a predicate multimethod

15:15 For ::integer it returns true if a value is an integer

15:15 For ::above-one it returns true if a value if above one

15:15 dbasch: ~oop

15:15 clojurebot: Titim gan éirí ort.

15:15 bbloom_: yeah, so "decomplecting" dispatch and evaluation, you need a multi-result on dispatch, then some combining function, then you can evaluate that

15:15 weavejester: So then I derive ::natural from ::integer and ::above-one

15:16 Yeah, essentially… (combine-f (map multi-f (ancestors dispatch-val)))

15:16 bbloom_: whenever you have multiple results, you can think about it as ambiguity

15:16 and you can resolve ambiguity by lifting in to a domain where it's explicitly ambiguous

15:16 weavejester: Not sure I follow that

15:17 bbloom_: um... hmm how to explain

15:17 weavejester: With normal multimethods, the choice is simply “choose the most specific dispatch”

15:17 bbloom_: instead of saying you're returning multiple results, you return one result with multiple values in it

15:18 weavejester: Yes… multiple values combined by some function. So you’d have a dispatch-fn and a combine-fn

15:18 bbloom_: yup

15:18 do you have a particular use case in mind?

15:19 the fundamental issue w/ predicate dispatch is one of ambiguity... you can't tell who to dispatch to if you don't have proof of logical implication... but that's when you want only a "most specific" method to match

15:19 i'm curious if you need a combining function that respects the lattice for matches... that is you need to combine such that the arguments to the combining function are in some order with respect to what a single-result dispatch would have produced

15:20 or if combining happens on a set

15:20 w/o order

15:20 weavejester: Yeah, I have two use-cases in mind. One would be a predicate multimethod, i.e. the combine-fn would be #(apply and %) or (every? identity %) I guess.

15:21 The other would expect a collection to be returned, and concatenate the collections, so the combine function would be concat

15:21 bbloom_: by every? identity, you mean you want to check if the logical conjunction of all the methods is true?

15:21 have you considered grammars?

15:21 weavejester: Grammars?

15:21 bbloom_: so grammars are basically what you want for the first thing

15:22 for the second thing, you need to worry about order

15:22 people think of grammars as being for parsing

15:22 but that's selling them short!

15:22 a grammar production can be interpreted as a predicate

15:23 weavejester: Oh, such as “is this syntax correct”?

15:23 In the most common case of parsers

15:23 bbloom_: yeah, basically "does this structure satisfy this grammar production"

15:23 you can use gramamrs on anything, not just text

15:23 and grammars can compose nicely

15:24 so if you're trying to test a logical disjunction, you can just union grammars... or a logical conjunction, you can just intersect grammars

15:24 gfredericks: clojurebot: bbloom is a fount of things you didn't know you didn't know

15:24 clojurebot: Ack. Ack.

15:25 bbloom_: the concat case is a lot more alien though...

15:25 weavejester: bbloom_: Do you have any links for further reading?

15:25 hiredman: it also sounds similar to logic programming, e.g. getting a collection of results back

15:25 bbloom_: hiredman: yup, hence mention of ambiguity

15:26 weavejester: Yeah. It’s not so much a concat as a set merge

15:26 bbloom_: weavejester: i've had a hard time finding good research on grammars for things other than parsing

15:26 weavejester: union rather

15:27 bbloom_: weavejester: you can search for the words "union" and "intersection" with respect to grammars

15:27 weavejester: I was experimenting with a system for representing realtime system state over a network

15:28 bbloom_: https://en.wikipedia.org/wiki/Context-free_language talks about stuff like compllement, intersection, difference

15:28 words suggestive of sets ;-)

15:28 weavejester: Essentially pulling ideas from datomic and representing the current state as a set of [e a v] triples, with an addition time component

15:28 dbasch: bbloom_: I know of someone who used context-free grammars to test circuit designs

15:28 bbloom_: dbasch: awesome

15:29 weavejester: I guess I have two broad goals

15:29 bbloom_: hmmm CFG are closed under union, but not complement, intersection, or difference

15:29 bummer :-P

15:30 weavejester: determine whether a message is valid given a current state, e.g. (valid? state msg) -> bool

15:30 And to work out the consequences, or reactions to a message

15:30 (reactions state msg) -> msg

15:30 I mean -> [msg]

15:30 hiredman: so, like, a rules system?

15:30 weavejester: Yeah

15:31 bbloom_: yeah, so validation systems are deeply related to grammars too

15:31 you've got some value and you need to analyze it to see if it satisfies some requirements

15:31 hiredman: https://twitter.com/aphyr/status/474627972641480704

15:32 weavejester: If a rule is a triple, [e a v], e.g. [:fred :age 30], and a state is a map {[e a v] -> t}

15:32 Or just a set #{[e a v t]}

15:33 Then I guess I both want to check if a rule can be added to the state - validation

15:33 And check what the effect of that rule will be

15:33 valid? :: state rule -> bool

15:33 aphyr: hiredman: pretty mad tbh

15:34 weavejester: reactions :: state rule -> [rule]

15:34 bbloom_: aphyr: what patch are you waiting on?

15:34 aphyr: dev.clojure.org/jira/browse/CLJ-1415

15:34 like I spent a full week writing this patch and providing extensive benchmarks

15:34 literally doubles performance

15:34 for json parsing

15:35 like this close to just forking Clojure into a real project on github and accepting community PRs

15:35 cuz jira and fighting git are taking up the bulk of my time

15:36 bbloom_: jira is a nightmare :-/

15:36 aphyr: yeah, I've also got low confidence that any of this work will pay off in a merge

15:36 like, unclear whether I should put in another N hours if it's just gonna go round in circles

15:38 bbloom_: i mean, it looks like a non-trivial patch & alex seems like he's being pretty cooperative... what's the real problem here? that it's not merged yet?

15:39 Viesti: I'm using postwalk to transform a json structure with dots in keys (mongodb doesn't like those) and it seems that postwalk is slow, is there a faster alternative, maybe transients?

15:39 bbloom_: weavejester: have you seen daedalus? and bloom/bud ?

15:40 weavejester: it's aimed at distributed use cases, but there's some interesting stuff in there for logic rules & communicative operations

15:40 weavejester: bbloom_: They don’t ring a bell

15:40 bbloom_: might be worth studying

15:40 http://www.bloom-lang.net/

15:42 but i guess that incorporates time, which you don't really care about yet... right?

15:42 weavejester: I do have a time component

15:42 bbloom_: hm

15:43 weavejester: Essentially I keep the state as {[e a v] t}

15:43 j0ni: technomancy: the rest of the project.clj is here https://gist.github.com/j0ni/b173f407fc30e41f05d3

15:43 bbloom_: yeah, def check out the paper on deadalus

15:43 weavejester: That way I can calculate continuous functions and expiry

15:43 bbloom_: maybe cemerick have some ideas from the CRDT world too

15:43 weavejester: Where is the daedalus paper?

15:44 Oh, I think I’ve found i

15:44 it

15:44 I was assuming it was Clojure at first

15:44 bbloom_: http://www.eecs.berkeley.edu/Pubs/TechRpts/2009/EECS-2009-173.html

15:44 i spelled it wrong

15:44 dedalus is right

15:45 j0ni: technomancy: let me know if there's some debugging activity that might help figure out what up

15:45 cemerick: bbloom_: long scrollback, it seems. What's the question? Ways to represent time in a distributed fashion?

15:45 weavejester: Essentially I have a system that takes events: [:assert/:revoke e a v t] and produces a state {[e a v] t} plus some indexes

15:45 bbloom_: cemerick: weavejester is exploring validation of states & transitions, i think

15:46 weavejester: cemerick: Yeah, essentially. A way of representing a current state that can be distributed across a network.

15:47 aphyr: bbloom_: yeah, alex is doing the right thing, it's just a ton of work is all

15:47 I forked clojure internally and that solved the problem

15:47 bbloom_: aphyr: it sucks that it's so slow, but ... yeah that's what i was gonna say: you can always run your own branch while you "wait"

15:47 aphyr: after a full week's work I got frustrated and didn't want to do any more

15:47 bbloom_: to me, the problem is that it's such a pain in the ass to fork & manage your own artifacts

15:47 weavejester: I’m just considering how to manage validations, i.e. is an event for a particular state valid, and reactions, i.e. what are the consequences of an event

15:48 bbloom_: which is a problem w/ a lot more than just clojure

15:48 basically everything

15:48 aphyr: absolutely agree, managing artifacts is a PITA, but less than jira

15:48 bbloom_: hence the desire to just run off the latest version from the primary maintainer

15:48 hiredman: sonian ran its own fork of clojure for a while, that may also have been keyword related

15:48 aphyr: And like N people in sidechannels have told me they'd support a fork on github

15:48 cemerick: weavejester: bbloom_ mentioned bloom/bud, and that's definitely interesting to tinker with; a Clojure impl would be pretty killer, but I've never investigated daedalus seriously

15:48 aphyr: I wanna do it, but tracking upstream is a timesink I don't want to deal with

15:50 tbaldridge: although tracking upstream isn't so bad on a project with as few commits as Clojure has.

15:50 perhaps once the two diverged enough

15:50 cemerick: weavejester: CRDTs certainly fit the bill as well, but that's not necessarily saying much. The hardest part is in reconciling the semantics you care about with the axiomatic requirements of CRDTs/semilattices. (ACI, etc)

15:51 weavejester: and unless you're happy to accept LWW, then you need a more subtle notion of time than wall clocks, etc

15:51 or, even then, given skew, etc.

15:51 weavejester: LWW or LVW?

15:52 cemerick: weavejester: Last Writer Wins; LVW?

15:52 weavejester: Oh, last value wins

15:53 I couldn’t work out the middle w :)

15:53 I’m essentially going for a client/server model, with the server maintaining the canonical state, and the clients being somewhat lossy

15:53 So time is server-time

15:54 A client connects, gets the approx. server time, then a dump of the current state {[e a v] t}

15:54 cemerick: weavejester: so the "clients" are retaining at least some portion of the data model, rather than making particular queries

15:55 ah, sure

15:55 weavejester: Yep. The whole thing, essentially.

15:55 Every so often the server will pass them the whole thing so they don’t deviate too much.

15:56 But usually they’ll accept [o e a v t] messages, where o is the operation, :assert or :revoke

15:56 This produces a state {[e a v] t}

15:57 cemerick: weavejester: Well, that's so close to replication, you might as well go all the way. :-P

15:57 weavejester: It essentially is replication

15:58 Where it gets fuzzy is that I have a function

15:58 (tick state time) -> state

15:58 cemerick: right, with pessimistic deltas occasionally, etc

15:59 everyone wants a pleasant distributed state machine :-)

15:59 weavejester: I also have functions:

15:59 (valid? state event) -> bool

15:59 (commit state event) -> state

15:59 technomancy: j0ni: try `lein deps :tree`

15:59 weavejester: (react state event) -> [event]

16:00 cemerick: weavejester: you have multiple concurrent actors touching shared data?

16:01 weavejester: cemerick: Yes, but the state can only be changed by commiting an event

16:01 hiredman: have you considered just implementing raft?

16:01 weavejester: Raft?

16:01 hiredman: the concensus algorithm

16:02 weavejester: Ah, found it

16:02 hiredman: you have a leader replicating a log of operations to followers, and when a quorum of followers have and operation it is commited

16:02 cemerick: weavejester: Well, you have two choices. You can either have a real consensus mechanism (like paxos/zk/raft) mediate those concurrent changes, or you can change the model to think in terms of convergent states as opposed to proposal->commit

16:04 In the latter, a "commit" of a valid state can be seen as simply marking a particular causal history.

16:04 weavejester: I was thinking just implementing a very naive first-one-wins approach for concurrent changes

16:05 hiredman: sure, but you want to replicate the changes?

16:05 weavejester: Yep

16:06 mordocai: Anyone know if the latest (think it was released today?) cider might be broken? I hadn't tried to use it in awhile. Relevant data on my setup here: http://pastebin.com/VbzZjgyX

16:06 hiredman: so a lot of concensus algorithms work on the baisis of replicating logs of operations and once a quorum has the logs, and advance the known commited operations

16:07 and once an operation is commited it can be applied to whatever state is being maintained in concensus

16:08 weavejester: hiredman: Yes. In this case the server takes an incoming message from a client, checks if it’s valid, relays it to all the clients and updates the internal state.

16:08 At regular intervals, the clients get the full state from the server, correcting any drift

16:08 hiredman: it may be just because I have been fiddling with raft, but that sounds a lot like it

16:09 weavejester: Raft seems more concerned with correctness than I am, reading through it

16:09 hiredman: if you don't care about stale reads, that sounds a lot like how, uh, that one implmentation of raft did

16:10 weavejester: if you don't use the raft protocol to do reads of the state, then it sounds even more similar

16:10 so you can tolerate "stale" reads

16:10 weavejester: Raft appears to be a protocol to manage distributed state, but in my case I have a single authority

16:11 hiredman: sure

16:14 cminus1: ls

16:14 lazybot: bin boot dev etc lib opt root srv usr var

16:25 dawkirst: hi, why does (doseq [ item '((1 2) [3 4] "D")] (prn item)) not work without the '?

16:26 gfredericks: dawkirst: it's a function call otherwise

16:26 while you're just trying to represent a list

16:26 justin_smith: (1 2) is not a function

16:27 dawkirst: ok got it. so if I had a function that returned a list, I'd just call it there right?

16:27 amalloy: justin_smith: well, 1 is not a function

16:27 justin_smith: that too

16:27 stompyj: 1, in fact, is the lonliest number

16:28 (inc stompyj)

16:28 lazybot: You can't adjust your own karma.

16:28 stompyj: NOOOOO

16:28 gfredericks: (dec stompyj)

16:28 lazybot: ⇒ 0

16:28 gfredericks: FTFY


16:28 arrdem: hahahaa

16:28 stompyj: (inc gfredericks)

16:28 lazybot: ⇒ 67

16:28 stompyj: well played

16:29 dbasch: dawkirst: yes, the second argument must be a seqable thing

16:29 amalloy: guys let's make (dec stompyj) a running joke. maybe people will finally hate him more than they hate so

16:30 dawkirst: thanks

16:30 gfredericks: I didn't even realizez so was a nick

16:30 amalloy: i don't know what the deal is with so either

16:30 arrdem: amalloy: the hatred of so is without bound

16:30 amalloy: $karma so

16:30 lazybot: so has karma -27.

16:31 arrdem: stompyj has some catching up to do

16:33 stompyj: lol

16:35 $karma bitemyapp

16:35 lazybot: bitemyapp has karma 16.

16:35 stompyj: interesting. What did so do to get ranked lower then the guy who has a clojure stacktrace as his twitter profile image

16:35 justin_smith: amalloy: which raises an old curiousity - has anyone made a language that was so pedantically mathematical that a number N treated as the function that compounds its argument N times?

16:36 stompyj: the highlighting is so so so annoying, if you have a client that highlights usernames

16:36 stompyj: ohhhhhhhhhh

16:36 wow

16:36 amalloy: well, i'd argue that's your client's fault

16:36 arrdem: justin_smith speaks for the erc-hl-nicks users

16:37 amalloy: justin_smith: isn't that exactly church encoding?

16:37 justin_smith: exactly, but what languages actually treat numbers that way?

16:38 amalloy: none that anyone uses

16:38 TimMc: justin_smith: I think some theorem provers do that, at least on the surface.

16:38 justin_smith: I figured

16:38 arrdem: justin_smith: smalltalk used church numerals.

16:38 justin_smith: I know. let's make Number implement IFn

16:38 TimMc: Peano numerals

16:38 justin_smith: smalltalk? ahh, right 5.do(...) or whatever

16:39 but does smalltalk also say that 5.5() is 25?

16:39 dbasch: in python you could multiply random things

16:39 justin_smith: right

16:39 dbasch: 3 * long should give you a longlonglong

16:40 as a type

16:40 justin_smith: nice

16:40 * weavejester considers a “motlimethod” library

16:40 justin_smith: lol

16:40 dbasch: 2 * float = double

16:41 arrdem: dbasch: that's just an issue of floating point error and single precision floats being silly..

16:42 gfredericks: ,Float/MAX_VALUE

16:42 clojurebot: 3.4028235E38

16:42 justin_smith: String / 2 = utf8 maybe?

16:42 gfredericks: ,Double/MAX_VALUE

16:42 clojurebot: 1.7976931348623157E308

16:42 dbasch: arrdem: I mean, you can come up with semantics for multiplying any type by a number

16:42 justin_smith: no, never mind

16:42 gfredericks: utf4

16:42 hey can we compress arbitrary data like this

16:42 justin_smith: well jvm uses utf16

16:42 dbasch: e.g. 3 * Person = Trio

16:43 at least in the SFW version

16:43 arrdem: dbasch: you can _define_ whatever you want, that doesn't mean you've granted it general meaning

16:43 * arrdem ponders the meaning of void*

16:44 amalloy: ,(/ String Character)

16:44 clojurebot: #<ClassCastException java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.Number>

16:45 gfredericks: I define multiplying a type by a number to be the identity function

16:45 * arrdem declares multiplication by types to be a compiler error, and declares jihad

16:46 amalloy: ((* 5 String) :foo) => :foo

16:46 dbasch: why shouldn’t (n x) be the same as (repeat n x)?

16:46 TimMc: gfredericks: I just discovered today that Java doesn't support UTF-7 by default.

16:47 gfredericks: TimMc: man I sure hope that doesn't exist

16:47 TimMc: https://en.wikipedia.org/wiki/UTF-7

16:47 gfredericks: aw crap

16:47 you let me down man

16:47 TimMc: Dashing your hopes and dreams since 2011.

16:47 dbasch: https://en.wikipedia.org/wiki/UTF-9

16:47 justin_smith: gfredericks: like so many terrible vile things, it is rooted in email

16:48 TimMc: dbasch: Ha!

16:48 justin_smith: https://en.wikipedia.org/wiki/UTF-ℇ

16:48 ergh: i'm trying to learn core.async; is there a way to say "give me everything that currently in the channel (as a vector?) and if there's nothing, give me nothing (empty vector), don't block"? am i trying to do something you're not supposed to?

16:48 TimMc: dbasch: Second paragraph is great.

16:48 gfredericks: I was thinking the other day about a number system that uses an increasing radix

16:48 the first digit is binary, the second ternary, etc

16:48 TimMc: For other horrifying things that actually do exist: https://en.wikipedia.org/wiki/UTF-EBCDIC

16:48 technomancy: $kill

16:48 lazybot: KILL IT WITH FIRE!

16:49 TimMc: gfredericks: Have you heard of balanced ternary?

16:49 gfredericks: maaaaaybe

16:49 weavejester: ergh: It does sound like you might be using core.async incorrectly

16:49 gfredericks: It sounds like it was interesting when I knew about it

16:50 weavejester: ergh: What’s your end goal?

16:50 TimMc: It's like having a set of ternary weights you can place on either side of a scale.

16:50 dbasch: TimMc: here, I improved it :P http://shrturl.co/I01U2

16:50 TimMc: dbasch: How so?

16:50 gfredericks: oh this doesn't sound familiar actually

16:50 ergh: weavejester: im making a game and i want to collect all the commands that happened during a frame in the interface module and then pass those to the gameplay code for processing

16:51 dbasch: TimMc: removed the April fools part

16:51 TimMc: https://en.wikipedia.org/wiki/Balanced_ternary

16:52 justin_smith: ergh: do you have some synchronization requiring that the messages wait and get chunked in a vector rather than showing up as produced?

16:52 ergh: why not put that on the receiver end via a queue, and just append the queue from core.async in that case?

16:52 Hodapp: number system with base phi is also kind of interesting.

16:52 ergh: justin_smith: hm, in every frame, i want to process all events that came in till then

16:52 amalloy: gfredericks: balanced ternary is neat

16:52 justin_smith: java.util.concurrent.SynchronizedQueue

16:53 Hodapp: https://en.wikipedia.org/wiki/Golden_ratio_base

16:53 tbaldridge: ergh: use alts! in a loop with a default

16:53 justin_smith: ergh: read the queue in the context where "frames" are a thing, let async things be async

16:53 tbaldridge: ergh: if you hand alts! a :default, then it will never block

16:53 TimMc: gfredericks: Increasing radix... so 123 would be 1*4^2 + 2*3^1 + 3*2^0?

16:54 tbaldridge: ergh: https://clojure.github.io/core.async/#clojure.core.async/alts!

16:54 amalloy: TimMc: you can't use 3 in the 0s position, if the radix is 2

16:55 ergh: tbaldridge: sounds like what i was looking for. thanks

16:55 amalloy: actually it should be radix 1, permitting only a 0 as the lowest digit

16:56 TimMc: amalloy: Nonsense. 30-base-2 is 6 in decimal.

16:56 augustl: anyone got some pure java key/value databases to recommend?

16:56 TimMc: augustl: Why pure Java, does it need to run in the same process as your app?

16:56 gfredericks: amalloy: TimMc: right, 123 is not allowed

16:56 dbasch: augustl: you mean local, distributed, in process?

16:57 augustl: TimMc: yeah that would be a plus

16:57 dbasch: in process

16:57 TimMc: because otherwise you could just use a Java driver

16:57 amalloy: gfredericks: isn't this increasing-radix like...non-distinct? there are multiple ways to represent the same number

16:57 gfredericks: amalloy: I thought of radix 1 in the first digit but it seemed silly

16:57 amalloy: which is problematic for number systems

16:57 gfredericks: amalloy: are you sure? even if you avoid 123?

16:57 dbasch: augustl: when I was at LinkedIn we built this https://github.com/linkedin/krati although I’m not sure what’s its current state

16:58 technomancy: augustl: berkeley db is supposed to be nice

16:58 dbasch: augustl: I know there’s a java port of leveldb, also not sure of the state

16:58 gfredericks: amalloy: oh maybe I haven't been specific enough

16:58 amalloy: i guess not. i keep forgetting how the increased radix works. i need to wriet some actual numbers down

16:58 augustl: thanks folks :) googling

16:58 TimMc: gfredericks: UTF-n is defined (but not always implemented) for n in 1 5 6 7 8 9 16 18 32

16:59 gfredericks: 0,1,10,11,20,21,100,101,110,111,120,121,200...

16:59 mordocai: Anyone know if cider for emacs is broken right now? I'm having issues, exhibited here: http://pastebin.com/VbzZjgyX

16:59 augustl: hmm, berleley db is agpl

16:59 dbasch: augustl: krati is Apache 2.0

17:01 amalloy: gfredericks: what number does 111 represent?

17:01 TimMc: gfredericks: 0,1,2,3,3,4,4,5,6,8,10,11,8.... on the fly, may be wrong

17:02 So 9 would be represented... 201

17:02 mordocai: augustl: The java edition of the berkeley db has a bsd looking license

17:02 augustl: dbasch: the docs link 404's so I guess it's not that active :)

17:02 gfredericks: amalloy: 1 + 2 + 6 = 9 I think?

17:03 mordocai: augustl: Scratch that, has a code redistribution clause

17:03 TimMc: Oh right, 2*3 not 3*3

17:03 gfredericks: yeah factorials are big in infimal

17:03 TimMc: "infimal"

17:04 * gfredericks tries to pretend he didn't just make that up on the spot

17:04 kzar: Dumb question but what's the best way to install Java for Clojure on a Debian Wheezy machine?

17:04 arrdem: 1) install leiningen, 2) ??? 3) become enlightened 4) profit

17:04 gfredericks: still needs java

17:05 awwaiid: kzar: I use "sudo apt-get install default-jdk"

17:05 mordocai: kzar: If you want oracle java then https://wiki.debian.org/JavaPackage. If you are fine with openjdk then apt-get install openjdk

17:05 dbasch: augustl: do you really need a k/v store for performance, or could you do with other kinds of embedded dbs?

17:05 augustl: dbasch: performance is not important :)

17:05 dbasch: augustl: then just start with sqlite or something like that

17:05 augustl: the thing I'm building is for self-hosting

17:05 TimMc: kzar: Wheezy is stable, right?

17:06 augustl: dbasch: would prefer to not have to do JNI, since that makes installing it a bit harder

17:06 awwaiid: actually, maybe kzar try "sudo apt-get install leiningen"

17:06 mordocai: TimMc: Sure is

17:06 augustl: then, suddenly.. I'll see if h2 has something :)

17:06 technomancy: awwaiid: erhm; that's not a good idea


17:06 dbasch: augustl: h2

17:06 mordocai: awwaiid: That is an old version of leiningen kzar

17:06 awwaiid: kzar: ok, based on technomancy please ignore my previous comment :)

17:06 augustl: hopefully it has a low level key/value store so I don't have to do sql and schemas :)

17:06 awwaiid: old yes. but does it work? seems to :)

17:06 TimMc: kzar: Yeah, just grab openjdk-7-* packages.

17:06 awwaiid: maybe I'm using unstable. oh. nevermind.

17:07 kzar: It better to use oracle or openjdk? (This is on my little server.)

17:07 amalloy: i would recommend against taking leiningen from apt

17:07 kzar: I'm guessing oracle Java is going to perform better?

17:07 technomancy: nah, use openjdk

17:07 amalloy: it's millions of years old, and won't work on many modern clojure projects

17:07 mordocai: technomancy: I was curious about that as well. So openjdk works fine in all cases or only most?

17:08 amalloy: openjdk is fine always

17:08 gfredericks: why was oracle mentioned then?

17:08 dbasch: amalloy: unless you’re trying to squeeze the last bit of performance for a large cluster

17:08 but for an individual project, sure

17:09 mordocai: I mentioned oracle in case kzar specifically wanted that since there is no package in the repositories.

17:09 augustl: h2 has something called a mvstore, http://www.h2database.com/html/mvstore.html

17:09 seems interesting to avoid sql

17:10 kzar: openjdk it is then, thanks y'all :)

17:11 gfredericks: okay I'm going to release this throw-data thing

17:11 who was it that wanted that

17:13 awwaiid: kzar et al -- I'm actually using a local lein, not the one in apt (despite it being installed). So yeah.

17:13 augustl: https://github.com/jankotek/mapdb looks nice

17:13 mordocai: awwaiid: Sounds like you are doing it right then :P

17:13 awwaiid: exactly!

17:15 augustl: both mapdb and h2 has a gazillion features I don't need..

17:16 dbasch: augustl: well, the filesystem is always an ok k/v store :)

17:16 augustl: dbasch: hehe :)

17:16 dbasch: only half joking

17:16 augustl: the only feature I do need is better than O(n) key lookup :)

17:16 dbasch: augustl: what are you storing?

17:17 augustl: dbasch: arbitrary bytes as both keys and values

17:17 dbasch: size of your stored blobs?

17:17 augustl: keys are small, values I'm not so sure about. Perhaps I'll have some sort of limit. But support for arbitrarily sized would be nice :)

17:18 dbasch: augustl: you can go a long way with a directory tree made of partial hashes in a decent fs, if you feel like reinventing a db

17:19 augustl: sounds like that means I have to manage lots of fun things, like hitting the max amount of dirs etc

17:19 think I'll just roll with h2, it's super stable and more than fast enough

17:20 dbasch: augustl: that’s what I would do, but I’d stick to sql unless you have a good reason not to

17:20 amalloy: augustl: have you looked at tokyocabinet? it's not java, but it's in process. at geni we used it, and wrapped it up in masai as a general byte-based kv store

17:20 augustl: yeah think I'll do that too

17:20 amalloy: got a link to that wrapper? :)

17:20 amalloy: $google clojure masai

17:20 lazybot: [ninjudd/jiraph · GitHub] https://github.com/ninjudd/jiraph

17:21 amalloy: really. fascinating

17:21 anyway, it's https://github.com/ninjudd/masai

17:22 augustl: amalloy: thanks, will check it out

17:22 amalloy: you'd use https://github.com/ninjudd/masai/blob/develop/src/flatland/masai/tokyo.clj to create a Tokyo TB, and then the stuff in https://github.com/ninjudd/masai/blob/develop/src/flatland/masai/db.clj to operate on it

17:22 augustl: JNI scares me :S

17:22 which I assume is what it ends up using

17:23 cbp: there are some issues with selmer that only happen with the openjdk

17:23 no one knows why

17:23 openjdk + fedora

17:23 amalloy: augustl: sure. https://github.com/ninjudd/tokyocabinet

17:24 and we did have segfaults sometimes, when we were hacking on it. i think what's out now is stable, but you do open yourself up to more problems when you use jni

17:24 cbp: https://github.com/yogthos/Selmer/issues/26

17:24 Frozenlock: I'm trying to run my clojure app on a small debian distro, but I get this error Caused by: java.net.ConnectException: Connection timed out-- at java.net.PlainSocketImpl.socketConnect(Native Method)

17:25 Any ideas why I can't access the socket?

17:26 augustl: amalloy: yeah, the JVM isn't a big fan of JNI it seems

17:26 dbasch: Frozenlock: what are you connecting to? That’s not enough information

17:28 justin_smith: Frozenlock: what is getting the error - lein? your app?

17:28 can other apps connect?

17:28 Frozenlock: I have 2 things connecting to localhost (port 47800 and 47999) and another connecting to the network on port 47808.

17:28 justin_smith: java -jar my-app

17:29 I can connect with ssh and also browse the Internet from it.

17:29 justin_smith: and you know that there is someone listening on each of those ports?

17:29 dbasch: what do you see if you telnet into those ports?

17:30 Frozenlock: Well my application is the one going to listen :-/

17:30 holo: ,(map str ["a" "b" "c"] ["d" "e"])

17:30 clojurebot: ("ad" "be")

17:30 Frozenlock: Like if I do 'lein ring server-headless 2000'

17:31 dbasch: ok, so what do you see if you telnet into your application when it’s running?

17:31 holo: howto return ("ad" "be" "c") instead, assuming when coll is empty, it yields nil?

17:31 I mean, is there an fn somewhere for this?

17:31 Frozenlock: dbasch: I can't run it, that's the problem. I get the error when trying to start it.

17:32 TimMc: holo: If you knew which coll was longest, you could use concat and repeat to fake it...

17:32 ,(map str "abc" (concat "de" (repeat "")))

17:32 clojurebot: ("ad" "be" "c")

17:33 holo: TimMc, dam that was fast coding thanks!

17:33 TimMc: Is that good enough for what you need? It's not general.

17:33 holo: TimMc, I don't know yet, but it's a good starting point even if it isn't. thanks :)

17:34 (inc TimMc)

17:34 lazybot: ⇒ 59

17:34 ArseneRei: Would there be any reason using swap! or reset! in a for loop would not let the value persist on an atom?

17:34 {blake}: What's a "named resource" and how do I go about making a file a "named resource"?

17:34 ArseneRei: http://pastebin.com/rF4jYaeh

17:35 dbasch: Frozenlock: can you refheap the code that fails?

17:36 ArseneRei: for is not a loop

17:36 ArseneRei: List comprehension…ah…

17:36 Frozenlock: dbasch: No, that's a uberjar application. I hoped to avoid installing lein and running my program piece by piece, by I guess I won't have a choice :-/

17:36 TimMc: holo: I almost feel like partition-all is relevant here, but I can't figure out how.

17:36 cbp: {blake}: where did you read this

17:37 dbasch: ArseneRei: almost certainly your list is not being realized

17:37 ArseneRei: dbasch: Should I use a loop/recur pattern?

17:37 arrdem: ArseneRei: doseq

17:37 dbasch: ArseneRei: it depends, what are you trying to do?

17:38 ArseneRei: dbasch: I'm writing a simplistic game loop to iterate over players, perform an action and update state.

17:38 {blake}: cbp: http://clojuredocs.org/clojure_core/clojure.java.io/resource

17:38 jamesnvc: hello, I’ve run into an issue with compiling clojurescript on the server under immutant, and I’m wondering if I should be filing a bug to clojurescript, immutant, or if it’s something I can work around

17:38 dbasch: ArseneRei: if your atom is defined outside of your loop, you can do an infinite loop with loop/recur

17:39 ArseneRei: that atom is inside the scope of your let, so it might as well not be an atom

17:39 {blake}: I've got an example where "(io/resource "response.xml")" returns "/home/blake/clojure/nzb/resources/response.xml", which is groovy, but I don't know how/why it came to point to the "resources" directory or how I can apply that to my current project.

17:39 ArseneRei: arrdem: I see what you mean. side-effects you want doseq.

17:39 hiredman: {blake}: n is the name of the resource, resources are loaded via classloaders

17:39 jamesnvc: When calling cljs.closure/build while running in an immutant context, cljs.js-deps/goog-resource fails to load the resources from the google-closure jar

17:39 holo: TimMc, I can't figure it out with partition-all. I never used that one before

17:39 dbasch: ArseneRei: unless you’re doing some multi-threaded stuff inside your let

17:40 cbp: {blake}: the directory resources inside your project.clj is added to your classpath. a "name" is a path into your classpath

17:40 ArseneRei: dbasch: Okay, so you're saying since it's a local variable the loop/recur pattern should be sufficient.

17:40 jamesnvc: Apparently because (ClassLoader/getSystemClassLoader) doesn’t get the right classloader here

17:40 (at https://github.com/clojure/clojurescript/blob/master/src/clj/cljs/js_deps.clj#L233)

17:40 hiredman: {blake}: it is because lein automatically puts a directory in the project root named resources on the classpath (and things in that directory get packged in to jars)

17:40 dbasch: ArseneRei: if you don’t have concurrency you don’t need an atom

17:40 ArseneRei: you could just recur with a new value

17:41 cbp: dbasch: I think a bit of mutabilty can make some algorithms much easier

17:41 jamesnvc: Using (.getContextClassLoader (Thread/currentTHread)) instead of getSytsemClassLoader works though

17:41 hiredman: {blake}: you cannot treat resources as mutable

17:41 TimMc: holo: Do you want the final call to str to be (str "c") or (str "c" "")?

17:41 hiredman: e.g. writing to a content

17:41 {blake}: cbp, hiredman Thanks...so...huh, I thought I did that...added a "resources" and re-ran.

17:41 jamesnvc: Is this an issue with clojurescript not using the right loader, or immutant doing things strangely?

17:41 hiredman: you shouldn't treat resources as being read from a file

17:41 ArseneRei: dbasch: Yeah, that makes sense. I'll remember that in the future. Thanks very much.

17:41 TimMc: I bet flatland/useful has somethign appropriate, by the way.

17:41 {blake}: hiredman, Mutable? I didn't intend to. Am I doing that somewhere?

17:42 justin_smith: {blake}: don't make a File out of a resource

17:42 hiredman: {blake}: oh, I am just looking at the clojuredocs example

17:42 justin_smith: because the resource could be in a jar

17:42 hiredman: terrible

17:42 justin_smith: get an input stream from the resource

17:42 amalloy: TimMc: it does, in fact

17:42 holo: TimMc, actually it's irrelevant :)

17:43 {blake}: justin_smith, This is just for sample purposes, to provide some data similar to what will be coming in from a SOAP call.

17:43 amalloy: nothing super-great, i guess. it'd be like (map (partial apply str) (zip "abc" "de"))

17:43 justin_smith: OK, still, use io/input-stream to get the contents, not io/file

17:43 holo: TimMc, but I guess (str "c") is more general

17:43 justin_smith: {blake}: because eventually that will matter

17:44 holo: TimMc, for ofther fns different than str

17:45 TimMc: amalloy: Do you still develop useful?

17:45 {blake}: justin_smith, this response should never see a file system. We're making a SOAP call, processing the value, passing it to some other webservice, getting the response back, pushing it back to the SOAP.

17:45 amalloy: TimMc: i haven't had a need to add anything to it recently, but it's mine and if there's anything general i want i'll put it there

17:46 justin_smith: {blake}: wait, then why does io/resource even come into question?

17:46 amalloy: most recent change was when glenjamin added docs for us

17:47 justin_smith: {blake}: my point is more that "if the thing is in your source repo, and you may every some day hypothetically make a jar, use io/resource to access it and don't assume it is a file"

17:47 s/every/ever

17:48 TimMc: holo: I tried to write up a quick "map-dregs" fn but it's surprisingly tricky.

17:48 holo: TimMc, I bet there is. meanwhile i'm playing with partition-all.. it's interesting, but hardly shorter than your solution

17:48 TimMc: Oh, did you get a solution that uses that?

17:48 holo: not yet but close.. it's getting big :(

17:49 TimMc, is map-dregs from useful?

17:49 TimMc: Naw, I'm writing it.

17:50 holo: oh you call it dregs haha :o

17:50 amalloy: TimMc: https://www.refheap.com/d35476b87b8239ea4fb4ff3fd ?

17:50 doesn't seem that hard to write

17:50 so presumably i missed something

17:51 could be shorter but i don't like repeated calls to apply

17:51 TimMc: amalloy: Does that give the same results for (map-dregs - [1 2 3] []) and (map-dregs - [] [1 2 3])?

17:52 ergh: when i have (recur) at the end of one of the branches of an if, it works. but when its at the end of one of the branches of cond-let, it says "Can only recur from tail position". why?

17:52 amalloy: sure, [-1 -2 -3] in both cases. shouldn't it?

17:52 TimMc: Oh, I see -- you filter every time instead of weeding out the empty colls.

17:52 hiredman: ergh: look at the macro expansion of the cond-let

17:53 {blake}: justin_smith, Thanks. It comes into play because I'm working on functions to operate on the structure returned, and trying to provide examples of real use. I don't have access to any of the WebService calls myself, just a "Here, this is what the data looks like" in a file.

17:53 amalloy: ergh: i can't imagine that cond-let is really what you want

17:53 ergh: heh

17:53 hiredman: ergh: cond-let isn't in core, so it is likely to be some random macro of dubious quality

17:53 amalloy: hiredman: there's one in contrib and one in useful. i can confirm they are both highly dubious

17:53 holo: TimMc, this is so cool. i'll take a couple of minutes to get it.. really awesome

17:54 hiredman: well, there you go

17:55 amalloy: TimMc: you could weed out the bad ones as a performance optimization. doesn't seem like it would change results in any interesting way

17:55 TimMc: *nod*

17:55 It's just the mindset I had when I was reading your solution.

17:56 holo: TimMc naming it dregs is totally cool too :)

17:56 amalloy: yeah, https://www.refheap.com/2adba5f6c4cae810891ca981b

17:59 stain: hi - what should I call a library that is wrapping a Java library? https://github.com/stain/owlapi-clj is wrapping net.sourceforge.owlapi/owlapi-contract -- now I've used (ns owlapi-clj.core) and owlapi-clj in project.clj - but I would want to tidy up before putting it in clojars

17:59 as it sounds silly to say -clj all over

18:00 Note that although I work in the floor below the OWL API guy, I am not affiliated with the underlying Java project

18:01 noonian: stain: i prefer clj-owlapi to owlapi-clj, but you could always just make up a silly name that has nothing to do with owlapi :P

18:01 TimMc: amalloy: Here's what I came up with. Almost the same, of course. https://www.refheap.com/86323

18:01 pellet :-P

18:01 on the silly names front

18:02 noonian: lol

18:02 amalloy: right. that's the most straightforward way to write it, but the repeated calls to apply are gonna kill you performance-wise, TimMc

18:02 TimMc: amalloy: I like the removal of apply by using the inner fn.

18:02 amalloy: apply is a lot less slow than it used to be in 1.4

18:02 but still kinda gross to call over and over

18:02 TimMc: Any thoughts on the filter vs. keep and next vs. rest?

18:02 stain: noonian: just worried people would not find it at all with a silly name.. I know that worked for cheshire (which heavily depends on jackson, which again is kind-of silly name for something to do with JSON :)

18:03 amalloy: using next is an error, because you realize one more element of the input seq than necessary

18:03 stain: noonian: but would you keep "clj" in the namespaces and clojars (e.g. maven) package name as well?

18:03 cbp: stain they can find it from your project description

18:03 amalloy: using filter instead of keep is just mildly slower, i would expect

18:03 sjl: stain: is it good

18:03 noonian: stain: yes, similar to clj-http

18:04 cbp: clo-*-jure is lame imo

18:04 sjl: if so call it "Superb Owl"

18:04 danielcompton: So clojuredocs is still on 1.3...

18:04 stain: sjl: no, it's like.. quite primitive at the moment :)

18:05 noonian: you can always change the name later in a new version, i think github will take care of linking the old project page to the new one

18:05 stain: back in the olden olden days I wrote a series of Python libraries called "forgetHTML", "forgetSQL" and "forgetSomethingelse" (I've forgotten what the last thing forgot!)

18:05 amalloy: stain: superb owl. super bowl. ye olde joke

18:05 Glenjamin: superb-owl is an awesome name

18:05 noonian: i like pellet or hooter

18:05 Glenjamin: twit (as in twit-twoo)

18:05 stain: "pellet" is already a well known OWL Reasoner

18:05 noonian: ah

18:05 nullptr: danielcompton: yeah, http://clojure.org/cheatsheet links to different sites depending on version...curious

18:05 stain: http://superb-owl.com/ hehe

18:06 TEttinger: bowl

18:06 bowel?

18:06 cbp: call it tootsie and have the tootsie pop owl picture in the readme

18:06 stain: TEttinger: for a sh.tty library

18:06 TEttinger: powell?

18:07 oh well?

18:07 stain: oh.. sh.tty -- that must be a terminal emulator written in sh!

18:07 danielcompton: nullptr: Github, Clojuredocs, Oracle

18:07 nullptr: M-x clojure-cheatsheet

18:07 Glenjamin: http://en.wikipedia.org/wiki/Category:Fictional_owls

18:07 i am surprised but delighted that that page exists

18:08 stain: well thanks for all your suggestions :)) I was mainly concerned about the "-clj" bit...

18:08 justin_smith: goddammit o rly? is not a fictional owl

18:08 stain: > Errol, an aged Great Grey Owl who serves as the family's courier. He has trouble carrying loads and is often found unconscious after collision or exhaustion.

18:09 technomancy: https://en.wikipedia.org/wiki/List_of_animals_with_fraudulent_diplomas

18:09 noonian: Glenjamin: thats my go-to webpage for choosing a name in rpgs when the main character is an owl

18:09 Glenjamin: i did the same thing for famous assassins once

18:09 Frozenlock: dbasch: lein repl returns the same error: java.net.BindException: Cannot assign requested address at java.net.PlainSocketImpl.socketBind(Native Method)

18:10 justin_smith: technomancy: brb signing up my neighbor's pug for a Clojure CA

18:10 Glenjamin: he'll struggle with the code review phase

18:10 stain: http://www.telegraph.co.uk/news/uknews/crime/9876199/Police-under-investigation-over-dogs-witness-statement.html

18:10 TimMc: amalloy: Hmm, point taken on next being too eager.

18:11 dbasch: Frozenlock: are you sure the port is not taken by another process?

18:11 justin_smith: "updated stack traces to include more snorting and licking"

18:11 TimMc: stain: That article begins with "However," -- I feel like I walked into the middle of a conversation.

18:11 SegFaultAX: Why does fnil have such a verbose definition?

18:12 Why not like (defn fnil* [f & rep] (fn [& args] (apply f (map #(if (nil? %1) %2 %1) args rep))))

18:12 Glenjamin: (doc fnil)

18:12 clojurebot: "([f x] [f x y] [f x y z]); Takes a function f, and returns a function that calls f, replacing a nil first argument to f with the supplied value x. Higher arity versions can replace arguments in the second and third positions (y, z). Note that the function f can take any number of arguments, not just the one(s) being nil-patched."

18:12 Glenjamin: oh, in code

18:12 (source fnil)

18:13 justin_smith: SegFaultAX: see also the source for map

18:13 stain: TimMc: however, the decline of journalistic language quality is ever increasing. You should try reading. Norwegian newspapers. They don't even complete. Sentences. Like this one.

18:13 Frozenlock: dbasch: doesn't 'lein repl' take a port at random?

18:13 justin_smith: SegFaultAX: it's for performance

18:13 gfredericks: Glenjamin: a lot of variadic core fns unroll some of their arities

18:13 justin_smith: $source fnil

18:13 lazybot: fnil is http://is.gd/9Lr9Rg

18:13 gfredericks: Glenjamin: and a few of them, like fnil, do it in two dimensions

18:13 amalloy: technomancy: where's the list of animals with legitimate diplomas?

18:14 gfredericks: I guess fnil isn't actually variadic though; but it's almost variadic

18:14 justin_smith: () <- hey look, I found it

18:14 {blake}: amalloy, https://shine.yahoo.com/pets/3-dogs-college-degrees-125400686.html

18:14 SegFaultAX: justin_smith: Yea.

18:15 technomancy: amalloy: it's wikipedia, go for it

18:16 dbasch: Frozenlock: yes, but before that it tries to evaluate your :main

18:16 Frozenlock: There's no main. It's just lein repl without a project

18:17 justin_smith: ok, then just before it gives you a prompt

18:17 dbasch: Frozenlock: can you paste the output of lein repl?

18:17 refheap?

18:17 clojurebot: https://www.refheap.com/

18:17 Frozenlock: https://www.refheap.com/86326

18:18 justin_smith: if you start the repl yourself you can easily specify a specific port to use - maybe this is also possible for "lein repl", I don't recall if I have tried

18:18 (start the repl yourself as in nrepl.server/start-server in your :main)

18:18 Glenjamin: lein repl :port <num>

18:18 dbasch: Frozenlock: btw, why are you running as root? Also, what does your /etc/hosts look like?

18:19 Frozenlock: dbasch: Because there's just root on this image.

18:19 brunov: Hey guys. I'm wondering, what do people use to deploy clojure apps to remote servers, typically?

18:19 justin_smith: ideally: make an uberjar and a shell script with the apropriate java options

18:19 Frozenlock: dbasch: It runs on an arm processor, I don't really mind running as root for now.

18:20 deathknight: :)

18:20 dbasch: Frozenlock: can you ping localhost?

18:20 holo: TimMc I quit trying partition-all for this for more than two colls. maybe loop/recur could do it, but i can't sort it out. thanks for your algo :D

18:20 amalloy: Frozenlock: IME "cannot assign requested port" means that all 64k ports on the machine are already assigned. check out `netstat -a`

18:20 deathknight: Is there a clojure IRC channel specifically for seeking help?

18:20 brunov: justin_smith: cool. I'm thinking of using capistrano and wanted to check here first in case there's something else I was missing.

18:20 arrdem: brunov: git with post-receive deploy scripts, or war

18:20 dbasch: holo: that would be trivial with loop/recur

18:21 brunov: arrdem: interesting idea!

18:21 dbasch: holo: you keep going while (or cur1 cur2 …)

18:21 Frozenlock: dbasch: Well sonofabitch, localhost doesn't respond

18:21 justin_smith: brunov: I guess capistrano could replace that above mentioned shell script, if you need things it provides

18:21 arrdem: Frozenlock: .... what on earth did you do to {firewall,/etc/hosts}

18:22 cbp: lol

18:22 justin_smith: the key being that building (with lein of course) does not happen on prod

18:22 kzar: Probably missing relevant line in /etc/hosts

18:22 deathknight: Quick question: If I wanted to find the value of :status in {:body {:status "test"}}, wouldnt this work? (it doesnt) -> [{{val :status} :body} args]

18:22 it returns nil

18:22 Frozenlock: arrdem: Nothing! I just took this image and assumed it was configured. https://www.olimex.com/wiki/A10s-OLinuXino-MICRO#How_do_I_write_the_Linux_image_to_a_micro_SD_card_to_use_with_my_A10S_board.3F

18:22 deathknight: (ex: (let [{{val :status} :body} args] (println val))

18:22 Frozenlock: Obviously I was wrong

18:23 holo: dbasch :> yes, I guess the point was not use loop/recur

18:23 cbp: configured to troll

18:23 amalloy: deathknight: that would work, if args were {:body {:status "test"}}

18:23 but i imagine args is actually [{:body {:status "test"}}]

18:23 deathknight: thats correct amalloy

18:23 as of right now, it returns nil

18:24 Frozenlock: /etc/network/interfaces ---> #auto lo, #iface lo inet loopback

18:24 *facepalm*

18:24 dbasch: (doc get-in)

18:24 clojurebot: "([m ks] [m ks not-found]); Returns the value in a nested associative structure, where ks is a sequence of keys. Returns nil if the key is not present, or the not-found value if supplied."

18:24 blr: brunov: you could look into pallet if you want a clojure solution (also for provisioning like chef etc)

18:24 dbasch: ,(get-in {:body {:status "test"}} [:body :status])

18:24 clojurebot: "test"

18:25 Frozenlock: Sorry for wasting everyone's time :-(

18:25 dbasch: don’t worry Frozenlock. But I suggest getting a rubber duck :P

18:25 justin_smith: Frozenlock: things like that are why I so often jump to - easy enough to remember, not as brittle as "localhost"

18:26 deathknight: clojurebot, sorry man. I just don't understand that

18:26 clojurebot: I don't understand.

18:26 stain: justin_smith: and on a rainy day, you can even get a way with

18:26 deathknight: Amalloy, how would I get the value of :status in [{:body {:status "test"}}]?

18:26 dbasch: ,(get-in {:body {:status "test"}} [:body :status]) ;; deathknight

18:26 clojurebot: "test"

18:27 cbp: prolly prepend a 0 if it's in a vector

18:27 deathknight: it is a map

18:27 just to be 100% sure, whats the command to check what data type it is?

18:27 justin_smith: sometimes -> is more readable than get-in

18:27 cbp: ,(type {})

18:27 clojurebot: clojure.lang.PersistentArrayMap

18:27 deathknight: it is a persistentarraymap

18:27 confirming

18:28 cbp: justin_smith: never!!

18:28 justin_smith: ,(-> {:body {:status "test"}} :body :status)

18:28 clojurebot: "test"

18:28 dbasch: ,(-> [{:body {:status "test"}}] first :body :status)

18:28 clojurebot: "test"

18:28 deathknight: justin_smith, where is the input for the arg?

18:28 justin_smith: yeah, that helps too

18:28 (doc ->)

18:28 clojurebot: "([x & forms]); Threads the expr through the forms. Inserts x as the second item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the second item in second form, etc."

18:29 amalloy: justin_smith: what. when would -> ever be more readable than get-in

18:29 dbasch: amalloy: I suppose if you had to do a bunch of stuff before the get-in

18:29 deathknight: (-> persistantArrayVariable :body :status) returns nil

18:29 justin_smith: amalloy: I find clearer thanks to less nesting, and being able to throw in something like first is a bonus

18:30 amalloy: dbasch: *shrug* (-> foo blah bar whatever (get-in [x y]))

18:33 dbasch: amalloy: yeah, I don’t have an opinion

18:33 cbp: justin_smith: (get-in [0 :a :b])

18:33 deathknight: {:body {:milestones {:status "test"}}}

18:34 arrdem: tools.analyzer uses the (-> {} :foo :bar first :baz quxx :val) format... it has its advantages, besides being gratuitous use of ->

18:34 justin_smith: cbp: doesn't work on list / seq

18:35 kzar: So I've built the nginx-clojure jar, where do I put it though? When I start nginx it stalls because it can't find the jar but the readme doesn't explain where to put it

18:36 Frozenlock: Ugh... any instances where 'java -jar uberjared.jar' doesn't run? I just get my shell prompt back

18:37 cbp: that doesn't necessarily mean it doesn't run

18:37 dbasch: kzar: it’s in the readme, in the configuration section: jvm_options "-Djava.class.path=jars/nginx-clojure-0.2.2.jar:jars/clojure-1.5.1.jar";

18:38 kzar: Right I've put those lines in the config file

18:38 dbasch: But that path looks relative jars/nginx-clojure-0.2.2.jar right?

18:38 Frozenlock: cbp: It would be running in the background but giving me the prompt back? (in this case it's not running in the background)

18:39 dbasch: kzar: that path is probably relative to /etc/nginx

18:39 cbp: Frozenlock: I have no idea what you have inside that jar but unless you have an infinite loop it gives you the prompt back

18:40 noonian: i think the example config assumes you put the jar in directory named 'jars' inside etc/nginx directory

18:40 dbasch: kzar: you could make it absolute

18:40 kzar: dbasch noonian: OK, I'll try putting them in /etc/nginx/jars/ and see what happens

18:40 1 mo

18:40 Frozenlock: cbp: I have a compojure app in it. I've ran it thousands of time and it never gave me the prompt back while it was running.

18:41 When all else fails.... reboot

18:41 cbp: oh nevermind you're right

18:41 then

18:45 kzar: Hmm that didn't work

18:46 blr: technomancy: that comment in #emacs reminded me, do you have any thoughts on how to best manage security notification for project deps? Feels like this is not handled very well by any system

18:46 and depending on system packages is clearly untenable, but works in terms of security

18:46 pip and gems suffer from this too, I think it's kind of universal

18:47 kzar: dbasch noonian: OK changing paths to absolute /etc/nginx/jars/... worked. Is that the proper place to put them though? (Seems weird having the jars in the coonfig dir and the fact that the default relative path didn't point there makes me question it.)

18:47 ergh: does clojure have some kind of support for synchronizing its datasctructures over the network?

18:47 blr: ergh: in terms of serialisation? there's edn

18:48 justin_smith: blr: maybe a way to tag an artifact in a repo as insecure, and a lein audit command to check a given project's deps?

18:48 noonian: kzar: it's totally up to you, clojure and nginx-clojure are probably the only jars you'll need for nginx so you could put them wherever

18:49 justin_smith: we should make the command to deprecate an artifact be "lein malign <version>"

18:49 ergh: i was thinking for exampke if youre changing a datastructure on a server and a client has it's own copy of that, you'd only need to send some sort of "diff"

18:49 blr: well, there's lein-ancient, but the onus is on the developer to run it regularly, and afaik there's no distinction between a feature and a security release

18:50 justin_smith: ergh: like some kind of networked version of persistent data structures' data sharing?

18:50 ergh: yeah

18:50 justin_smith: ergh: if you used datomic for the coordinating of values, I think you would get that

18:50 blr: ergh: I think the 'quilt' project is potentially related to your query, but afaik there's not much information about it currently

18:51 justin_smith: ergh: though that is not the same as sending an update point to point

18:51 technomancy: blr: haven't really given it much thought. I think there's a security mailing list, but I don't know if they've got this use case in mind

18:51 justin_smith: maybe send an "update please" message to the peer, and send the change to datomic?

18:52 blr: technomancy: right, it feels like a big gap in every tooling ecosystem I'm familiar with.. with ruby and python you just have to keep an eye on mailing lists and hope that you catch something

18:53 wish we had something as rigourous as debian's security releases

18:54 justin_smith: blr: related, someone should make an updater / package manager than manages all your package managing updaters

18:54 * blr has an aneurysm

18:55 technomancy: blr: well debian is different because you typically don't have people employed full-time to pay attention to many systems.

18:57 blr: sure.. although maybe there's some merit to justin_smith's suggestion of being able to 'taint' a dependency, which lein could provide a warning for?

18:58 technomancy: gpg has support for revoking keys, I wonder if there's any mechanism for revoking signatures.

19:00 blr: go-lang 'solves' this by having everything on edge, pointing to master on github :P

19:00 justin_smith: since .m2 is a cache, maybe a "purge this value from the cache" model is apropriate?

19:01 technomancy: blr: http://p.hagelb.org/blam.gif

19:01 justin_smith: blr: go-lang development sounds fun

19:01 a real roller coaster

19:01 technomancy: for serious issues we can consider straight up clojars deletion

19:02 justin_smith: right, but remember it gets cached in everyone's .m2/

19:02 Frozenlock: blr: Are your serious?!

19:02 amalloy: if we're deleting clojars, can i hold a flamthrower?

19:02 justin_smith: which is why some way of checking for things to purge would be nice

19:02 technomancy: yeah

19:03 justin_smith: maybe friendlier to make a .m2/dont-use-these-insecure-packages-but-here-they-are-for-reference/ directory and move things there

19:04 andres-v`: requestnames,createaccount,customer_account,assign_name,create_client,toggle_ban_client,deleteclient,rqn_new,rqn_xactiontype_selected,rqn_bank_selected,rqn_book_selected,rqn_customeraccount_selected,rqn_newcustomeraccount,rqn_registernewcustomeraccount

19:08 blr: food for thought at any rate, feels like something that could be better

19:10 technomancy: blr: it's unlikely that much will happen if you don't make it happen at this point

19:11 blr: technomancy: fair enough. Do you think the idea's worth exploring?

19:11 technomancy: blr: yeah, I believe so.

19:11 the incentives around it are kinda pathological though unfortunately

19:11 blr: in what sense?

19:11 technomancy: it takes a big bad incident to get people to actually care, at which point it's too late

19:12 blr: oh right, yeah that's always the way with security

19:14 Frozenlock: At least nobody got #=ed... I think...

19:17 stain: clojars - I just get "Invalid PGP public key" at https://clojars.org/register - my PGP key is A0FFD119 and I've tried exporting it as gpg --export -a 0xa0ffd119

19:20 justin_smith: that is a really small public key

19:20 stain: it's 597 lines in the export

19:21 justin_smith: ahh, never mind, I misread

19:21 stain: hm, I registered with an empty PGP Public key, and then went to update the profile, and it worked OK

19:21 kzar: So with nginx-clojure is the idea that you build your clojure project that includes your ring handlers to a jar and have nginx-clojure use that? (Each deploy you'd build a new jar for your project and put it in place?)

19:22 justin_smith: kzar: yeah, I think so. An uberjar that includes all your deps, of course.

19:23 err... wait, this is looking different

19:24 noonian: kzar: i've not used nginx-clojure and that might be what you need, but if you are just trying to serve an app with nginx i think most people just do a simple reverse proxy to an embedded java server in the clojure app. http-kit has good documentation with examples on how to do that.

19:25 justin_smith: (inc noonian)

19:25 lazybot: ⇒ 4

19:25 justin_smith: yeah, nginx clojure looks nifty and all but I am not sure how much it really gains you over having a separate clojure process

19:26 amalloy: from what i've seen of nginx-clojure it's a bit wacky

19:26 hiredman: totally wacky

19:26 justin_smith: oh, it lets you put clojure code in the config, lol

19:27 you can even put your handler code inline in your nginx location definition

19:27 how "useful"

19:27 amalloy: dare i say, gonzo bonkers?

19:27 justin_smith: https://github.com/nginx-clojure/nginx-clojure#231-inline-ring-handler

19:32 deathknight: If I have {:body {:milestones [{:status 1} {:status 2}]}}, how can I create a collection of the values for each :status?

19:32 I know how to get the value of the first status

19:33 justin_smith: (->> m :body :milestones (map :status))

19:33 deathknight: holy CRAP

19:33 YOU ROCK

19:33 justin_smith: no kind sir, Clojure rocks

19:33 amalloy: inside voices

19:34 deathknight: nnnnnnnng

19:37 justin_smith: eventually you will likely want to doseq on that map, if this is you http://stackoverflow.com/questions/24071746/creating-a-collection-of-multiple-same-depth-values-in-a-nested-hashmap

19:37 in the doseq you could push the proper sync

19:38 haha, small world, now I see what's going on

19:38 deathknight: I am noisesmith on stackoverflow

19:40 deathknight: Justin!

19:40 Holy crap!

19:41 Hahaha

19:41 I'm smiling so hard

19:56 kzar: Sorry was AFK there, so general consensus is to use http-kit + nginx instead of clojure-nginx?

19:57 amalloy: well, use anything+nginx

19:57 whether http-kit or something else is the server you want is up to you

19:57 but i would not touch nginx-clojure

19:58 kzar: Only thing is if you run a server process with something like http-kit how do you make sure that process keeps running?

19:59 amalloy: clojure doesn't just randomly crash every five minutes

19:59 kzar: In the past when I've done similar things with Python/Ruby instead of using nginx modules like passenger I've run into that problem

19:59 so you don't have something checking it's still running?

Logging service provided by n01se.net