#clojure log - Sep 26 2011

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

9:37 Blafasel: Totally new, playing with 4clojure.com right now. At one point I'd like to get a number (int?) from a char. I guess I could resort to the java parsing methods. Is there an alternative? A 'clojure way' or some sorts?

9:37 kzar: ,(Integer "12")

9:37 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.RuntimeException: Expecting var, but Integer is mapped to class java.lang.Integer>

9:37 kzar: ,(Integer. "12")

9:37 clojurebot: 12

9:38 kzar: Blafasel: I think that is the normal way to go about it, I've seen it done like that in bits of code I've been reading

9:38 Blafasel: Thanks a lot

9:40 khalig: anyone use lamina? i can't seem to find the receive-all function

9:41 kzar: Blafasel: I found it suprising too, the rule seems to be if the Java way works OK it's idiomatic to use it.

9:41 Blafasel: k, that simplifies the learning curve for some things here. Dear god, I hope no one is looking at the code I'm submitting to that site. :)

9:43 kzar: Blafasel: Heh, me and you both

9:48 fdaoud: Blafasel: which problem are you working on?

9:50 Blafasel: fdaoud: Uhm - already past it, no idea how to get back to the original thing.. It was something like 'multiply two numbers and return the product as a sequence of single digits.

9:51 I could show you my approach (feedback would be great), but I don't want to spoil the question for anyone?

9:53 kzar: Blafasel: IIRC I did something like this:

9:53 ,(map (comp #(Integer. %) str) (seq (str "12345")))

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

9:53 kzar: (Oops of course I didn't mean to quote that 12345 number)

9:55 fdaoud: I love Clojure, but the number one thing with which I get burned is when something is lazy and I was expecting it to get called

9:57 raek: fdaoud: then use 'doseq' instead of 'for' and (dorun (map ...)) instead of 'map'... :-)

9:57 fdaoud: raek: you're right.. and doall (repeatedly ...)

9:58 I got burned on that last one because the first time I used repeatedly, it so happened that it was being passed as an arg and consumed so it got called

9:59 Blafasel: Hmm. My lisp exposure so far is near zero, my functional experience limited to F#. I get a headache clicking on any 'source' link in the clojure docs so far.

10:09 fdaoud: Blafasel: another resource: http://java.ociweb.com/mark/clojure/article.html

10:21 Blafasel: Hrmpf. This feels like butchering the language. I can solve ~most~ problems so far, but ..

10:30 kzar: Hmm it seems to work OK including the old contrib with Clojure 1.3

10:36 pdk: 1.3 released

10:37 my world is rocked

10:37 is contrib updated too

10:38 kzar: pdk: In a sense, they've changed it around a bit http://groups.google.com/group/clojure/browse_thread/thread/c00088794dfdeaf5

10:38 pdk: hm

10:38 do you have binaries for all of the contrib repos packaged together

10:46 kzar: Has anyone used the couchDB library Clutch with Clojure 1.3 yet? I'm getting this error "clojure.lang.KeywordLookupSite.<init>(ILclojure/lang/Keyword;)V

10:46 [Thrown class java.lang.NoSuchMethodError]" when I try and require com.ashafa.clutch

10:49 cemerick: Just saw you join, any idea how to get clutch working with Clojure 1.3? I get an error when I try and require it now (both 0.2.4 and 0.2.5-SNAPSHOT)

10:51 cemerick: 0.2.4 is not 1.3 compatible. 0.2.5-SNAPSHOT is.

10:52 make sure you flush your project's lib directory and do `lein deps` again when you change dependencies (assuming you're using lein)

10:54 kzar: cemerick: Hmm so I did `lein clean`, made sure I've got 0.2.5-SNAPSHOT in project.clj, did `lein deps` again. Started REPL but I'm still getting an error when requiring clutch

10:56 cemerick: http://paste.lisp.org/display/124879

10:56 gfredericks: I'm trying to write a simple http proxy that simply adds a few headers to requests, then forwards them to another server. I tried this with ring + clj-http, but the difference in the interfaces is getting hairy. I'm starting to think it's simpler to do it at the TCP level. Would aleph be appropriate for this?

10:58 cemerick: `lein clean` does not touch lib AFAIK; can you make sure that /lib contains only v0.2.5-SNAPSHOT of clutch, and no other rev?

10:59 kzar: cemerick: Ah right, hmm looks like it's been cleared anyway: http://paste.lisp.org/display/124879#1

11:01 cemerick: oh, crud

11:01 somehow, AOT classfiles from clojure-contrib slipped into the clutch 0.2.5 SNAPSHOT jar :-(

11:02 IceD^: just checking - is there any proper way to use current slime (20110617) with swank-clojure?

11:03 kzar: cemerick: Balls, sounds like a bugger - although I've got no idea what that means to tell you the truth heh!

11:03 cemerick: yeah; you shouldn't have to!

11:03 kzar: I'm going to have to ping Tunde and get him to push a fixed build.

11:04 kzar: cemerick: OK, thanks for looking into it

11:08 Blafasel: Code works locally, fails with a (cryptic.. *sigh*) error message on 4clojure.com: java.security.PrivilegedActionException: java.lang.ClassCastException: clojure.lang.PersistentVector cannot be cast to clojure.lang.MapEntry

11:13 Can anyone shed some light on potential problems with this code here? Both "My eyes!!" comments as well as explanations regarding that ClassCastException would be greatly appreciated: http://pastebin.com/iyEA1DtZ

11:14 IceD^: anybody?

11:18 lnostdal: functional programming is a real pain when building macros; don't really need that there

11:21 i guess with-local-vars is the way to go there

11:24 TimMc: IceD^: I can't tell if cemerick at __:03 was responding to you.

11:24 cemerick: IceD^: Sorry, no, I was talking to kzar

11:25 manutter: Blafasel: looking at your code now...

11:25 * cemerick knows *nothing* about slime

11:25 TimMc: (same here, unfortunately)

11:26 Blafasel: You are way overthinking that 4clojure problem, for one.

11:27 manutter: Blafasel: I don't see anything technically wrong with your code -- it might not be optimal, but it should at least work

11:28 * manutter wonders if Blafasel is tickling some kind of bug in the clojure version running at 4clojure.org

11:28 TimMc: Blafasel: Works in my 1.2 REPL.

11:29 cemerick: Is there a password reset on clojars? Perhaps I'm blind…

11:29 gfredericks: cemerick: profile?

11:30 cemerick: but it only works if nobody has ever uploaded a jar with the groupname 'cemerick'

11:30 Blafasel: TimMc: Same here. Overthinking: Probably... :)

11:30 cemerick: gfredericks: can't get there if I can't log in :-)

11:30 gfredericks: cemerick: oh nevermind then :)

11:30 TimMc: Blafasel: My golf score on that problem is 21.

11:30 gfredericks: I read "reset" as "change"

11:30 Blafasel: manutter: Suggestions for improvements welcome - but you think that it should work as well?

11:30 TimMc: Ouch.

11:30 cemerick: gfredericks: yeah, I'll just try to catch ato next time he's around

11:31 manutter: Blafasel: yeah, should work. Come to think of it, this could be a sandbox bug too

11:31 Blafasel: I could think of a reduce of some sorts maybe..

11:31 kzar: Blafasel: Not sure if you saw, I got d/c there. My take on your solution was #(Math/round (reduce + (map-indexed (fn [i d] (if (= \1 d) (Math/pow 2 i) 0)) (reverse %))))

11:32 manutter: Blafasel: I think (reverse s) should help with something

11:32 Of course, if you're going for the golf score, the most "successful" solution might not be the most efficient

11:32 TimMc: Mine is pretty efficient.

11:33 Blafasel: Sure. I like both targets :)

11:33 TimMc: manutter: And you could also make a non-deterministic solution by using "random".

11:34 manutter: TimMc: Heh, I'd like to see that one

11:34 TimMc: Or use cemerick's equals-everything solution.

11:34 kzar: oh I replaced Math/round with int and I got a gold score of ~75

11:34 TimMc: clojurebot doesn't fail on Blafasel's solution

11:35 manutter: Yup, there's a bug somewhere at 4clojure.org I'd say

11:36 TimMc: Wait, cemerick's (or was it chouser's?) trick won't work here.

11:40 gfredericks: $findfn (promise) false

11:40 lazybot: Execution timed out.

11:42 TimMc: $findfn 2 2 4

11:42 lazybot: [clojure.core/unchecked-multiply clojure.core/+ clojure.core/* clojure.core/unchecked-add]

11:43 joly: ,*clojure-version*

11:43 clojurebot: {:interim true, :major 1, :minor 3, :incremental 0, :qualifier "master"}

11:46 zerokarmaleft: TimMc: it was chouser's

11:49 Blafasel: TimMc: Pfff.. Code Golf Score: 73

11:50 And I thought I'd be clever this time.

11:51 The new version.. Not sure about efficiency, but seems more readable even. http://pastebin.com/eLducDuQ Is that the direction I should take?

11:54 kzar: Blafasel: You could get rid of the brackets around int I reckon

11:55 TimMc: Blafasel: Do you want a hint?

11:56 Blafasel: Also, use apply instead of reduce.

11:57 I like the use of map-indexed.

11:59 Blafasel: Good catch. apply and brackets save 3 chars and I get to 70. But still... ;-)

11:59 TimMc: apply is also more efficient here

11:59 Blafasel: I'd even consider this readable so far. But my creativity is limited. Let's look at what clojure/core has to offer..

11:59 Why's that?

12:00 TimMc: reduce invokes + repeatedly. apply gives + the whole thing and lets it decide how to do the math.

12:00 Blafasel: Ah. Thanks

12:01 gfredericks: TimMc: is that definitely more efficent for +?

12:01 TimMc: Could be.

12:01 In practice, maybe not!

12:01 gfredericks: haha

12:02 I looked at the source for +

12:02 TimMc: However, reduce is never going to be *more* efficient.

12:02 gfredericks: actually...

12:02 TimMc: &source +

12:02 lazybot: java.lang.Exception: Unable to resolve symbol: source in this context

12:02 TimMc: ,(source +)

12:02 clojurebot: Source not found

12:02 TimMc: meh

12:02 gfredericks: it calls reduce :)

12:02 TimMc: Yeah, figured.

12:02 gfredericks: so I would say reduce is more efficient since you avoid the extra wrapper :P

12:02 TimMc: ha

12:03 Benchmark, benchmark, benchmark.

12:03 gfredericks: And I suppose inlining won't apply here.

12:05 gfredericks: TimMc: no idea

12:05 cemerick: TimMc: That was chouser's :-)

12:06 TimMc: yeah

12:16 Why does this not print [1 1 1 1 1]? (read-string "#=(vec (repeat 5 1))")

12:16 Instead, I get '[repeat 5 1]

12:16 kzar: Oh, where did source and doc go in Clojure 1.3?

12:17 TimMc: repl

12:18 manutter: TimMc: does (read-string "#=(vec #-(repeat 5 1))") work?

12:19 oops, that's #= in the second bit there too

12:19 not #-

12:27 kzar: Is there a way to do something like this? (defn (symbol "bad-example") [] (+ 1 2))

12:29 ipostelnik: kzar, why?

12:29 kzar: aka define something with the name of the value of a dynamic string

12:30 bsteuber: kzar: use a macro

12:31 kzar: bsteuber: Oh yea, cool that works

12:40 amalloy: TimMc: #= doesn't evaluate arguments

12:57 TimMc: amalloy: Fascinating.

13:00 Is that behavior documented?

13:03 ,#=(+ 2 2)

13:03 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.RuntimeException: EvalReader not allowed when *read-eval* is false.>

13:04 amalloy: TimMc: that #= works at all is only barely documented

13:05 TimMc: http://clojure.org/reader is the place, I guess

13:05 It should be documented quite clearly due to the security implications.

13:05 read-string also needs a note about *read-eval*

13:14 (I have my CA printed out and filled in, but I haven't sent it off yet...)

13:44 amalloy: suppose i want to write a function that takes any number of args, but unroll a couple of the early cases for performance. say, (defn sum ([] 0) ([x] x) ([x & ys] (+ x (apply sum ys))))

13:44 it's kinda awkward to have to treat x in the last arity specially; it would be nice if i could just have the last arity take [& xs], but not conflict with the other arities

13:45 technomancy: amalloy: (apply sum x ys)

13:45 only the last arg of apply is unrolled

13:46 amalloy: technomancy: yeah, i know

13:46 technomancy: oh you're talking more generally

13:46 amalloy: but i still have to mention x, and if the actual handling is more complicated than just calling apply

13:46 technomancy: yeah, I don't think there's a way around that unfortunately

13:46 TimMc: Technically, isn't [x] the same as [x & xs] for a 1-argument call?

13:47 ,((fn [x & xs] xs) 5)

13:47 clojurebot: nil

13:47 TimMc: So that's an example of a potential conflict that is already avoided.

13:47 amalloy: TimMc: i don't follow

13:48 TimMc: Oh, just that the compiler already knows how to distinguish between potentially ambiguous targets.

13:49 I don't see a reason [], [x], [& xs] shouldn't be allowed.

13:53 amalloy: TimMc: right, which is what i'd like

13:55 i agree it seems like it should be possible. looking at things, i think you'd have to make fairly significant changes to RestFn and at least some to fn

13:56 and i guess to the compiler too, since it generates instances of RestFn

13:59 in other words, probably not a fun change to make

14:10 chouser: what would be the harm in letting numerator return its arg when it's an integer?

14:10 and denominator return 1

14:11 hiredman: well, for anything non-ratio?

14:11 chouser: sure

14:11 hiredman: sounds good to me

14:14 amalloy: chouser: better to call rationalize instead? then it would work for doubles as well

14:18 gfredericks: I did not expect aleph to be difficult :(

14:18 * gfredericks does not know how to create a HeapByteBuffer

14:18 amalloy: $google java nio bytebuffer

14:18 lazybot: [ByteBuffer (Java Platform SE 6)] http://download.oracle.com/javase/6/docs/api/java/nio/ByteBuffer.html

14:19 amalloy: but you shouldn't need to create a HeapByteBuffer specifically; it should accept any kind of ByteBuffer? i haven't really used aleph, but it seems weird to even make you deal with ByteBuffers at all

14:20 gfredericks: amalloy: ah yes I think this is the case.

14:20 I did not expect that the factory for a HeapByteBuffer would be in the abstract superclass

14:20 go OOP

14:20 amalloy: It is definitely weird to deal with byte buffers

14:21 I'm not sure if it's necessary for what I'm doing...I'm kind of just being safe I think.

14:21 amalloy: i mean, they're java's high-performance io, so it's not totally implausible that aleph would let you work with them

14:21 gfredericks: aleph uses them if you don't specify a frame type

14:21 amalloy: but it doesn't seem like it would *make* you. mind linking to some code, or something in aleph you're using that needs this?

14:22 gfredericks: amalloy: I'm trying to make a basic http proxy that adds some headers to all requests

14:22 I started off trying it with clj-http+ring, but that seemed way too hairy

14:22 so now I'm trying to do it at the TCP level

14:23 and I assume that HTTP bodies can contain arbitary binary data

14:23 so I didn't want to deal with strings

14:24 I think that is a good summary. I can put together some code if you still want to see it.

14:24 amalloy: nah. i don't really know enough about aleph for it to be worth your time informing me further

14:24 gfredericks: kay.

14:47 srid: i eval'ed something in the slime repl that in turn launches threads (via future). where would the stdout of that thread go? I don't see it in the repl at all

14:47 bhenry: *lein-swank* ?

14:48 srid that was directed for you to check that buffer.

14:48 srid: no such buffer. I use `cake swank` (terminal) and M-x slime-connect (emacs)

14:48 bhenry: does the terminal have anything?

14:48 i've never used cake

14:48 srid: no, cake swank spawns the jvm/repl in background and returns immediately

14:48 technomancy: in swank-clojure 1.3.3 when launched with lein swank it will alter-var-root on *out* so that it will go to the slime buffer of the latest client to connect

14:49 srid: you mean the *slime-repl Clojure* buffer? should I update it?

14:50 oh, you are talking about lein swank.

14:50 technomancy: right, it will only work in 1.3.3-SNAPSHOT if whatever calls the start-server function passes in the optional flag to redirect output

14:52 it's possible cake would let you pass in arbitrary arguments to that function

14:54 ninjudd: technomancy: cake actually doesn't call start-server directly :/

14:55 it is hacked to call start-swank-socket-server! so swank doesn't have to run in your project classloader

14:56 technomancy: i should probably put together a patch for swank-clojure allowing you to pass a wrap-fn for socket-serve so i don't have to do evil things like that...

14:57 technomancy: hm; well as long as opts is passed through then setting the relevant flag should do the trick

14:57 or that

14:57 :repl-out-root true

14:57 srid: ninjudd: any workaround meanwhile? or should I switch to lein swank?

14:58 * dpritchett is sorely tempted

14:58 ninjudd: you can run 'cake log' to tail the log. it should have the output you're looking for

14:58 dpritchett: i'm finding that ~40 lines is the point at which i start thinking any JS file should really be rewritten in coffeescript

14:59 gotta try clojurescript soon

15:00 * manutter inherited a .js file with 1600+ lines in it.

15:01 amalloy: manutter: surely you mean one line, with 200k characters on it?

15:01 manutter: oh well sure, after you minify it

15:01 if we dared...

15:02 amalloy: minification is such a funny concept to me. i guess it makes sense in an interpreted language that you serve over the wire, but it's just so silly

15:02 gfredericks: amalloy: only thing sillier is maxification

15:03 ibdknox: gfredericks: I really like maxification.

15:03 Blafasel: TimMc: Okay, I _had_ to cheat on that binary thing and even then I only got down to 20.

15:03 TimMc: Are you seriously telling me that you have a nice, somewhat idiomatic solution in 23 chars?

15:04 ibdknox: gfredericks: it's the only way to make sure you have all your bases covered ;)

15:04 dpritchett: wait are people minifying 4clojure answers somehow?

15:05 * dpritchett backs away slowly

15:05 Blafasel: dpritchett: For fun and profit! ;-p

15:05 amalloy: Blafasel: you were having some problem with 4clojure earlier?

15:05 Blafasel: amalloy: ~depends~. I had code that worked in the repl but didn't on that site. Does that count?

15:06 amalloy: https://github.com/4clojure/4clojure/issues/71 has been known for a while, and from your paste looks like you ran into it

15:06 Blafasel: I improved the code a lot afterwards and the _better_ code worked :) So - no problem

15:06 amalloy: basically, in 1.2.x, you can't (eval (macroexpand '(case ...)))

15:07 Blafasel: amalloy: Sounds like it, yeah (that eval quote of yours is black magic/voodoo to me so far I've to admit)

15:07 amalloy: But - in that case a ban (or a 'case probably won't work' warning) would be a great intermediate step

15:08 amalloy: Blafasel: *nod* we just never found a good way to...mention it, in a place where it would make sense

15:08 gfredericks: (def maxify (partial wk/postwalk (partial list 'identity)))

15:08 Blafasel: I've to admit that I tried to solve most of the (tiny) problems so far by typing random things in that input box, looking at the clojure 1.3 docs at the same time. You were my repl and if you say 'Nope, that is crap' although it isn't: Sad panda.

15:08 amalloy: gfredericks: prewalk would really maxify it

15:09 Blafasel: amalloy: Understood.

15:09 amalloy: &(macroexpand '(case 1 2 3))

15:09 lazybot: ⇒ (let* [G__13737 1] (case* G__13737 0 1 0 0 (throw (java.lang.IllegalArgumentException. (clojure.core/str "No matching clause: " G__13737))) {0 [2 3]} false))

15:09 gfredericks: amalloy: you mean both together, or prewalk instead of postwalk?

15:09 amalloy: gfredericks: prewalk instead

15:09 should expand infinitely, i think. maybe postwalk does too, but that's less clear to me

15:10 gfredericks: amalloy: definitely blew the stack

15:10 amalloy: the postwalk one is quite tame

15:10 Blafasel: Great. From voodoo to gibberish.

15:10 gfredericks: ,(let [maxify (partial clojure.walk/postwalk (partial list 'identity))] (maxify '(+ 3 (* 4 5) 4)))

15:10 clojurebot: #<CompilerException java.lang.RuntimeException: java.lang.ClassNotFoundException: clojure.walk, compiling:(NO_SOURCE_PATH:0)>

15:10 amalloy: Blafasel: basically. case is a macro built into clojure, so it expands into some other code. normally, you can eval whatever code you want, but case has a bug that means the code can't be executed if you've macroexpanded it manually

15:11 gfredericks: &(let [maxify (partial clojure.walk/postwalk (partial list 'identity))] (maxify '(+ 3 (* 4 5) 4)))

15:11 lazybot: ⇒ (identity ((identity +) (identity 3) (identity ((identity *) (identity 4) (identity 5))) (identity 4)))

15:11 Blafasel: So it's like a kettle that only boils if you don't watch it? :)

15:11 amalloy: hah. yes, something like it

15:12 gfredericks: unfortunately gzip probably cuts out most of the space the identities take up, so most of the benefit is lost

15:14 Blafasel: TimMc: If you wake up I'd be curious about your 'codegolf' version. My cheat uses the java classlib now and only shoves off 3 chars of yours, I cannot imagine doing _anything_ meaningful in a functional way in 23 chars for that..

15:15 amalloy: Blafasel: you should be able to follow him and see it yourself

15:17 Blafasel: amalloy: He doesn't seem to use the same nick :)

15:17 amalloy: And there's no feature to look at the codegolf submissions, right?

15:17 amalloy: shortest solution looks like 17 characters

15:17 Blafasel: Wah?

15:17 amalloy: assuming we're talking about http://www.4clojure.com/problem/122

15:18 Blafasel: We are.

15:18 amalloy: follow youz, if you want to see the shortest possible solution for every problem on the whole damn site. that guy is incredible

15:18 Blafasel: And I considered 20 based on java alone cheating already :)

15:19 amalloy: darren has an equally-short solution, and is usually also pretty short, if you're into that

15:19 TimMc: Blafasel: Mine is 21 chars.

15:19 Blafasel: amalloy: Okay, all these guys are cheating like me :)

15:19 TimMc: 20 here, but - what are you doing?

15:20 TimMc: I used Integer/parse

15:20 amalloy: not cheating at all! clojure is hosted, and java is your friend

15:20 Blafasel: I know, I know..

15:20 TimMc: It's not cheating. Using the Java libs is fine.

15:20 Blafasel: But - learning clojure is something else :)

15:20 TimMc: Not using the Java libs is good for the exercise.

15:20 amalloy: there are some problems where you can do things that are pretty close to cheating, but we encourage these sorts of mild hacks

15:20 Blafasel: TimMc: #(Integer/valueOf # 2) is 20

15:21 TimMc: hah

15:21 I can get 24 without using Java libs.

15:21 Blafasel: Pics or it didn't .. - erm: paste!

15:22 amalloy: eg, a fun trick is to have your solution be multiple forms, instead of just a single function. see, for example, youz's solution to http://www.4clojure.com/problem/88

15:23 TimMc: amalloy: How do you do that?

15:23 (See other users' answers, that is.)

15:23 Blafasel: #(read-string (str "2r" %))

15:23 amalloy: TimMc: if you've solved the problem yourself, you can see answers from any user you follow

15:23 TimMc: follow?

15:23 amalloy: follow from the profile page at http://www.4clojure.com/user/youz

15:23 this is a newish feature

15:24 TimMc: Is this some newfangled Twazzer thingmabob?

15:24 amalloy: i hope not

15:24 Blafasel: amalloy: Didn't solve that yet. Vodka and beer on my desk. Let me see..

15:24 TimMc: or whatever you kids are calling it these days

15:24 Blkt: good evening everyone

15:26 amalloy: Blafasel: well, you can see a similar example in amcnamara's (or my) solution to http://www.4clojure.com/problem/23

15:33 ibdknox: amalloy: huh, learn something new everyday. I thought you always had to quote to get an empty list, which in retrospect is dumb of me

15:34 amalloy: ibdknox: meh. you do have to in scheme and CL, even though it's equally silly there. not an unreasonable assumption

15:34 TimMc: ibdknox: Amusing result of that decision: #()

15:34 ,#()

15:34 clojurebot: #<sandbox$eval17434$fn__17435 sandbox$eval17434$fn__17435@1d664>

15:34 TimMc: ,(#())

15:34 clojurebot: ()

15:34 ibdknox: haha

15:34 gtrak`: weird

15:35 TimMc: That's how the macro expands.

15:35 (fn [] ())

15:35 gtrak`: ,(fn [] ())

15:35 clojurebot: #<sandbox$eval17490$fn__17491 sandbox$eval17490$fn__17491@30114>

15:36 gtrak`: ,((fn [] ()))

15:36 clojurebot: ()

15:38 TimMc: So (#(constantly ())) is redundant, but (#(constantly 5)) is not.

15:38 amalloy: Could 4clojure make up its mind about www vs. no-www?

15:39 gtrak`: ,(#(constantly ()))

15:39 clojurebot: #<core$constantly$fn__3684 clojure.core$constantly$fn__3684@1a0476f>

15:39 amalloy: TimMc: well, we currently accept both. would you like us to do something different?

15:39 gtrak`: TimMc, not sure what your distinction is there.. maybe you want a fxn that returns an empty list instead of an empty list?

15:39 TimMc: gtrak`: Erm, never mind.

15:39 gtrak`: ,(())

15:39 clojurebot: #<ClassCastException java.lang.ClassCastException: clojure.lang.PersistentList$EmptyList cannot be cast to clojure.lang.IFn>

15:39 gtrak`: yea

15:39 TimMc: Got some levels confused.

15:40 amalloy: My password manager thinks there are 4 different sites (when you include http/s), and logging in on one does nothing for the others.

15:40 You effectively have 4 websites with a shared back end.

15:41 gtrak`: i love that the clojurescript compiler is one file

15:43 TimMc: gtrak`: I was thinking of identity, not constantly.

15:44 dnolen: gtrak`: ClojureScript compiler is pretty neat all around.

15:44 gtrak`: yea, just been looking at it, that browser repl is super-powerful, too

15:45 amalloy: TimMc: yeah, i'm aware that that's the basic behavior. we could 301 redirect one of the domains to the other, i guess

15:45 gtrak`: ,(identity ())

15:45 clojurebot: ()

15:46 amalloy: but i don't want to force either http or https

15:46 TimMc: Yeah.

15:46 gtrak`: TimMc, even with 'identity' in place of 'constantly', I'm not sure I get what you're saying

15:47 TimMc: amalloy: I'd be pretty happy if all you did was change the cookies to always have host=4clojure.com (no www)

15:47 amalloy: hm

15:47 i don't know how to do that, though

15:47 TimMc: amalloy: But a 301 (302 at first) redirect would be good too.

15:48 amalloy: why 302 at first?

15:48 TimMc: In case you want to change your mind.

15:48 I always put in a 302 for the first month or so, in case I have made a mistake.

15:48 301 instructs browsers, proxies, and spiders to permanently update their records.

15:49 (unless I have them reversed)

15:49 amalloy: TimMc: no, you're right

15:50 Blafasel: amalloy: Submitted a new twist of the 17 char solution..

15:50 amalloy: i read somewhere that if we're canonicalizing on one domain, it should include the www. this way we don't have whole-host cookies, and can set up a cookieless subdomain

15:50 Blafasel: But .. seems like that's the end of it :)

15:50 TimMc: I wish we didn't have this www/no-www dichotomy, but the result is that every top-level website has to deal with it. :-(

15:50 amalloy: TimMc: btw, we actually have 8 servers, not 4 - .org also works :)

15:50 TimMc: >_<

15:50 ibdknox: lol

15:51 jaskirat: does any one know if its possible to declare a java class field annotated as @Autowired using gen-class or some other mechanism?

15:51 * TimMc 'A'liases some more hostnames to 4clojure

15:51 ibdknox: amalloy: for some DNS's having the www. will also prevent a second look up making the site "faster"

15:51 TimMc: excuse me, CNAMEs

15:51 A is address

15:52 amalloy: Blafasel: i can't really go look at it without knowing your username

15:52 Blafasel: Right.

15:52 amalloy: ibdknox: yeah, i think our dns is set up so that that's not an issue, but i could be wrong

15:52 TimMc: Blafasel: My username here is timmcBasis. At home it is TimMc or maybe phyzome.

15:52 Blafasel: Instead of #(BigInteger. % 2) you can go for #(Long/valueOf % 2)

15:52 Problem: Same thing -> 17 chars

15:53 amalloy: *nod* darren's solution, which i pointed you at, does that, i think

15:53 Blafasel: Tried to find anything smaller, but..

15:53 amalloy: Oh.. The one's I'm subscribed to right now don't. And the shortest is the youz version w/ BigInteger.

15:53 Sry, must have missed that.

15:55 There's no way to have something a la '1L' in clojure, right?

15:55 (not (long 1) please, that's - erm - too long)

15:55 TimMc: 1N...

15:56 Blafasel: TimMc: Try-Clojure says 'invalid number'

15:56 TimMc: How about 1M?

15:56 amalloy: (a) ew, (b) 1N is new in 1.3

15:56 TimMc: haha

15:57 Blafasel: TimMc: 1M is a bigint, works.

15:57 TimMc: ,(class 1M)

15:57 clojurebot: java.math.BigDecimal

15:57 TimMc: ,*clojure-version*

15:57 clojurebot: {:interim true, :major 1, :minor 3, :incremental 0, :qualifier "master"}

15:58 gfredericks: ,(type (numerator 1/2))

15:58 clojurebot: java.math.BigInteger

15:58 Blafasel: ,(class 1N)

15:58 clojurebot: clojure.lang.BigInt

15:58 TimMc: Blafasel: 1.3 introduces BigInt

15:58 Blafasel: That's not available on 4clojure, right?

15:58 amalloy: right

15:59 gfredericks: ,(count "(numerator 1/2)")

15:59 clojurebot: 15

15:59 amalloy: i've explored upgrading to 1.3 and it's just a huge pain. i would be deliriously happy to accept a patch from someone else that does it

16:00 Blafasel: Right. Someone that knows clojure. Any takers? :-p

16:00 gfredericks: amalloy: break the task up into 4clojure exercises, and...

16:00 Blafasel: Dammit. Wanted to exploit calling a static method on an instance and remove the long with 1l or something..

16:00 amalloy: gfredericks has a point :)

16:01 gfredericks: it'll be just like recaptcha

16:05 Blafasel: There's a nice short story from Doctorow where someone trains an AI by sending spam and evaluating the response. Better result -> fitter ;)

16:16 Why does (.toString 1) work, while (.toString 1 2) doesn't (the latter ~could~ resolve to a static method, no?)

16:17 amalloy: Blafasel: the ability to call static methods as if they were instance methods is part of javac

16:17 Blafasel: amalloy: Ah. Dammit, another cheat ruined :)

16:17 amalloy: you could add code to clojure.lang.Reflector to make it work, but it's not really a great idea anyway

16:17 Blafasel: No, it's not.

16:17 amalloy: clever idea though

16:17 Blafasel: It's just a way to shove of some chars.

16:17 #(.valueOf 1 % 2)

16:17 would've been nice

16:17 amalloy: *nod*

16:18 Blafasel: (for certain values of nice...)

16:18 amalloy: by the way, there is a #4clojure channel. i don't imagine #clojure minds discussion of 4clojure, but you can come hang out with us too if you want

16:23 arohner: I have a lein plugin listed in dev-dependencies, and its in checkouts/, but I'm getting "That's not a task". Is that supposed to work?

16:28 bhenry: arohner you have to lein plugin install org.lein-plugin "version-string" or something like that

16:29 $ lein plugin install lein-clojars "0.6.0"

16:29 then tasks become available

16:30 ljos: Hi - I'm wodering something. I have a project and I have to do some of it in Java, but some parts of it does not necessarily need to be Java and I would like to use Clojure for it. What I'm wodering is what is the easiest way of making a mixed project? What IDE/editor would you use? Are there any best practices for this kind of projects that are written some where? Do I need to package the Clojure code into a jar to call it from Java or is it possible to do in

16:30 arohner: bhenry: I know the "normal" way to do it, I was hoping to avoid the install + deps cycle because I'm writing the plugin

16:30 but symlinking the plugin's src into my project's source worked

16:30 technomancy: arohner: plugins have to be known before the outer JVM launches, so you can't calculate them within clojure code.

16:32 arohner: technomancy: then how come symlinking the code into my project worked? symlinking lein-foo/src/leiningen into my-proj/src/leingen/ works just fine

16:34 technomancy: arohner: src/ is always on the classpath

16:35 choffstein: If I create an uberjar, is there a way to make sure the .clj files don't get added?

16:35 arohner: technomancy: ok, now I'm confused. "lein classpath" showed that my checkout plugin was in the path too. Was it lying?

16:35 technomancy: "lein classpath" tells you your project's classpath

16:36 Blafasel: Stupid question: Why are the 'source' links in the clojure docs still linking to Rick's github repository, which is outdated according to the header/readme?

16:36 technomancy: tasks in plugins must run in leiningen's own JVM, the classpath for which must be calculated in bin/lein

16:36 Blafasel: Is that a recent change?

16:36 arohner: technomancy: ah. ok, thanks

16:36 technomancy: doc/PLUGINS.md explains more

16:37 amalloy: Blafasel: that github repo has been defunct for ages. if you see anywhere that you can replace them, go for it

16:37 technomancy: ljos: mixed-source projects are not hard; just add a :java-source-path key to project.clj and leiningen will pick them up

16:37 belun: hello

16:38 (defrecord Comment [text]

16:38 2.

16:38

16:38 3.

16:38 NodeStreaming

16:38 4.

16:38 (stream [node strategy out]

16:38 5.

16:38 (write out "<!--" text "-->")))

16:38 what is 3. here ?

16:38 clojurebot: No entiendo

16:38 belun: protocol ?

16:38 NodeStreaming

16:38 su bot :P

16:38 amalloy: jesus. never do that. please put huge code snippets on gist.github.com or some similar paste service

16:38 belun: aaah the snippet again

16:39 amalloy: to answer your question, it is either a protocol or an interface

16:40 belun: ok thx. so when howard

16:40 http://java.dzone.com/articles/changes-cascade-and-cautionary#comment-form

16:40 says that the inners of a record

16:41 are carried as vals

16:41 inside protocol definition

16:41 who does that ?

16:41 the record or the protocol

16:41 inside protocol declaration

16:41 **

16:42 Raynes: Sentences can all be on one line.

16:43 belun: huh ?

16:43 nea timestamp ubbers it :P

16:43 if u have it...

16:47 so anyone understand my question or i'm talking gibberish ?

16:47 TimMc: It's hard to tell what your question is -- use more punctuation!

16:48 amalloy: clojurebot: punctuation is preferred to a torrent of newlines

16:48 clojurebot: Roger.

16:48 Raynes: Less enter, more period.

16:53 belun: so, if you create a protocol and attach it to a record, when delaring the record you have to implements its methods (corresponding to the protocol). now inside the body of these methods, apparently you have vals created for you

16:54 those vals are representatives of the record's fields (as seen in the post http://java.dzone.com/articles/changes-cascade-and-cautionary#comment-form)

16:55 so, who created these vals for me, the defrecord or the defprotocol ?

16:59 and an example on gist https://gist.github.com/1243395

16:59 dnolen: belun you don't attach a protocol to a record, you extend a type to a protocol.

16:59 belun: an by vals do you mean access to the fields?

16:59 belun: yes

17:01 dnolen: so the term is not "attach", but "extend", right? the technique is the same, though

17:01 dnolen: defrecord is a fancier version of deftype, deftype supports, 1) defining fields, 2) implementing methods of a protocol

17:02 bhenry: how would one check for equality in value and type?

17:02 amalloy: bhenry: .equals is usually enough, i think

17:02 ,(.equals () [])

17:02 clojurebot: true

17:02 amalloy: hm

17:03 &(every? true? (apply map = ((juxt identity class) [] ())))

17:03 lazybot: java.lang.IllegalArgumentException: Wrong number of args (2) passed to: core$identity

17:04 belun: so if i want to put that gist on clojuredocs, where should i put it? on defrecord or defprotocol? (my guess is defprotocol)

17:04 amalloy: meh. that's probably too complicated anyway; just check if the classes are equal and then if the objects are equal

17:06 belun: eeem, functions inside protocols are methods or functions ?

17:09 TimMc: belun: protocols create functions

17:10 In your example, "drinky-drinky" is a function.

17:11 belun: TimMc: but it is attached to a protocol :( doesn't it have a special name ?

17:12 TimMc: Not sure what you're asking.

17:13 The protocol has a name, and the functions have names. The protocol manages dispatch of calls to those functions based on what types it has been extended to cover.

17:14 belun: TimMc: like in Java, a function that is defined inside a class is a called a method of that class. and same goes for a procedure. in clojure, a function attached to a protocol is called ... ?

17:14 upwardindex: ahhhh forward declarations?! the clojure gods have cursed us! why oh why?

17:14 TimMc: upwardindex: declare?

17:14 upwardindex: yes that is the cause of my sadness

17:15 amalloy: there are a number of good reasons clojure requires forward declarations. not least of these is that, if you need a declare, you are probably doing something wrong anyway

17:15 TimMc: belun: Java doesn't *have* functions -- they're just called methods.

17:16 upwardindex: i can't seem to find any good reasons besides the JVM, please enlighten me amalloy

17:16 belun: TimMc: java's functions are methods (i learned pascal first). i have to abstract upwards :P

17:17 hiredman: upwardindex: why would the jvm require it?

17:17 amalloy: it means the compiler can treat a program as a stream of characters, instead of a big interconnected mess of files

17:17 upwardindex: amalloy: we might want to communicate these good reasons for forwards decls to the people working on the next common lisp standard, that feature is lacking

17:17 TimMc: amalloy: Like a REPL. :-)

17:17 hiredman: upwardindex: clojure is not common lisp

17:18 amalloy: (defn foo [x] (bar x)) is an error RIGHT NOW unless bar is already defined

17:18 in CL, it's just fine, cause who knows, maybe you'll define bar later

17:18 dnolen: upwardindex: has nothing to do w/ the JVM, long threads about it on the mailing list, plus the kind of nastiness that is avoided by lacking them.

17:18 gtrak`: yay spelling errors!

17:19 upwardindex: dnolen: thanks I'll have a look there for more information

17:19 gtrak`: upwardindex, early binding

17:20 upwardindex: However it does prevent from using a top-down approach in programming which you can't in many languages but is so sweet

17:20 gtrak`: what's top-down mean in this context?

17:20 amalloy: upwardindex: lisp encourages bottom-up anyway

17:21 TimMc: gtrak`: bottom-up is when you define your building blocks first

17:21 joly: both should refer to how you approach solving the problem, not the order you define the functions

17:21 upwardindex: codinghe high level functions first

17:21 amalloy: really? I always thought the opposite

17:21 gtrak`: you can use protocols and define interfaces to your functions... is that not it?

17:21 TimMc: When LISPers pick up a novel, they always skip to the end of the book first and work backwards.

17:21 amalloy: upwardindex: have you read On Lisp?

17:22 upwardindex: amalloy: No unfortunately, I read PCL though

17:22 anyways, I still love clojure

17:23 amalloy: in the intro: "The theme of this book is twofold: that Lisp is a natural language for programs written in the bottom-up style, and that the bottom-up style is a natural way to write Lisp programs"

17:23 upwardindex: I'm just saddened that its not as DRY as I first thought

17:23 TimMc: upwardindex: declare is kind of a last resort

17:23 amalloy: upwardindex: it is. don't repeat yourself: write your primitives first

17:23 TimMc: You don't have to use it!

17:24 amalloy: upwardindex: also, On Lisp has a gorgeous writing style. PCL is useful, but i really enjoyed On Lisp

17:24 upwardindex: amalloy: reading the primitives first is not always the best way…

17:24 amalloy: so skip to the bottom and read going up

17:24 reading (declare) first is *definitely* not the best way

17:25 brehaut: upwardindex: then write your primatives in another namespace

17:25 amalloy: that too

17:25 upwardindex: amalloy: ah so what TimMc said about lispers was really about clojurians! :P

17:25 amalloy: sigh

17:25 upwardindex: just having fun here, don't take me too seriously

17:26 TimMc: upwardindex: Clojure is a LISP.

17:26 upwardindex: brehaut: that is very clever, thanks for that suggestion i like it a lot more than declare

17:27 amalloy: anyway, book is at http://lib.store.yahoo.net/lib/paulgraham/onlisp.pdf in case you were not aware. well worth spending some time on even if you never write CL

17:27 i certainly don't

17:28 dnolen: upwardindex: if you've ever dealt w/ CL symbol interning, Clojure tries to avoid that. So we lose something and we get something.

17:30 the other big benefit is capturing common typo errors w/o requiring whole program analysis - worth the price of admission IMO.

17:32 upwardindex: On another note, what are the best sources of news for clojure besides planet clojure?

17:32 brehaut: related: benefits of F#'s significant compile order http://cs.hubfs.net/forums/13172/ShowThread.aspx#13172

17:33 upwardindex: http://disclojure.org/

17:33 dnolen: brehaut: nice

17:35 belun: re: deftype/protocols. Methods in Java are not first class. Clojure gives polymorphism w/o losing the power of functions.

17:36 amalloy: upwardindex: also the google group, and irc

17:37 belun: will videos from last strangeloop be available anywhere ?

17:37 gtrak`: belun, they will gradually be released over time on infoq

17:38 dnolen: belun: will take a long while from what I hear. But I suspect they'll put keynotes up first.

17:41 srid: i have a bunch of modules with "initialize" function (that spawns a future and what not). see example - http://dpaste.com/621560/

17:41 what is the recommended way to "manage" these futures so I can shutdown or restart on them?

17:42 I use REPL to development, so I really must shutdown existing components (read: futures and what not) before launching them again

17:43 vojd: win 7

17:43 technomancy: man... if only there were a restart-agents function.

17:43 vojd: sorry :( irssi fail

17:43 srid: one solution is to use atoms to store futures, http://groups.google.com/group/aleph-lib/msg/18df7972f68cd3ed but I don't if this accepted

17:43 don't know*

17:45 i am forced to do 'cake killall', relaunch swank and everything :(

17:45 gtrak`: can you force them to get garbage collected by re-binding the vars?

17:46 * srid earlier had troubles cancelling a future using future-cancel (it was still running), so he couldn't write a "shutdown" function

17:46 ibdknox: sounds like you should be using a pool

17:47 srid: is pool a language construct or external library?

17:49 ibdknox: http://stackoverflow.com/questions/5397955/sleeping-a-thread-inside-an-executorservice-java-clojure

18:42 mjg123: Hi all. I'm trying to find a way to take a zip file (on the classpath) and unzip its contents to a given directory

18:43 is there anything you know of that can help me?

18:43 or just bash through with java interop

18:47 ibdknox: mjg123: I don't know of any real solutions other than Java interop, a quick search turned this up though: https://github.com/ToddG/experimental/blob/master/clojure/doc01/src/doc01/zip.clj

18:48 amalloy: mjg123: java's zip files are pretty awful; you might consider shelling out to bash instead, if you know that bash will exist and you'll have permissions

18:48 mjg123: ibdknox, thanks, read that one :)

18:49 technomancy: mjg123: you can do it in about 10 lines; see Leiningen's leiningen.jar/extract-jar defn

18:49 mjg123: amalloy, that's fine, bash is there. But the file isn't, it's on the classpath (ie inside the jar)

18:49 ibdknox: amalloy: yeah looking at that code made me a little sick :p

18:51 mjg123: technomancy, thanks.

18:52 shep-home: Say I had a sequence and I wanted to number each item AND know what the max number was

18:52 mjg123: technomancy, so I'd have to create a JarFile from the URL given by classpath.getResourceAsStream?

18:52 shep-home: I could use something like map-indexed and then find the last item

18:52 but that seems... inelegant

18:53 brehaut: ,((juxt (partial apply max) (partial apply +)) [1 2 4 3])

18:53 clojurebot: [4 10]

18:53 amalloy: shep-home: reduce is your best choice, i think

18:54 brehaut: whoa, amalloy didnt recommend juxt!

18:54 shep-home: brehaut: I'll get back to you in an hour or so when I grok that :-)

18:54 amalloy: brehaut: i didn't get the impression he wanted to sort them

18:54 ibdknox: yeah

18:54 that's not what he asked

18:55 technomancy: mjg123: maybe. try it out.

18:55 amalloy: &(let [items '(a b c)] (reduce (fn [[i acc] x] [(inc i) (conj acc x)]) [0 []] items))

18:55 lazybot: ⇒ [3 [a b c]]

18:55 shep-home: An example would be [:a :b :c], then I get something like [[:a 0] [:b 1] [:c 3]] and know that 4 would be the next number

18:55 amalloy: &(let [items '(a b c)] (reduce (fn [[i acc] x] [(inc i) (conj acc [x i])]) [0 []] items))

18:55 lazybot: ⇒ [3 [[a 0] [b 1] [c 2]]]

18:56 shep-home: yeah, kind of like that

18:56 ok, now I'ma go sit in the corner and meditate on these solutions

18:56 thanks!

19:01 Two questions about that last bit of code, amalloy

19:02 ipostelnik: is there a quick way to clear names loaded into slime repl?

19:02 so if I rename a function the old name disappears from the repl

19:02 shep-home: 1: is using reduce where the types of the two parameters differ normal/idiomatic

19:02 technomancy: shep-home: very common

19:03 shep-home: 2: is packing two values into a vector like that normal/idiomatic?

19:03 technomancy: thanks, I guess I'm a bit limited in thinking of it as the same

19:03 amalloy: yes, when you need to keep track of multiple things, working with a tuple is the easiest way

19:04 ipostelnik: see ns-unmap

19:04 shep-home: I suppose that the small scope of the tuple makes it better

19:05 if it were to be more exposed, would a map be better?

19:05 and/or more idiomatic?

19:05 non-homogeneous collections worry me :-)

19:06 technomancy: it's probably a bit better to assoc it into a map as you go, though it's easy enough to pour a seq of k/v pairs into an empty map when you need it.

19:07 brehaut: shep-home: http://hackage.haskell.org/package/HList

19:08 shep-home: theres no reason heterogenous collections need to be unsafe ;)

19:15 ipostelnik: amalloy, that let's me unmap one thing at a time

19:19 amalloy: you didn't ask for anything more specific

19:20 ipostelnik: well, is there anything more convenient than ns-unmap?

19:21 can I unmap a whole namespace at once?

19:21 grim_radical: in anger, I've used remove-ns

19:21 brehaut: ipostelnik: even if theres not, you can write your own

19:22 eg (map (comp (partial ns-unmap *ns*) first) (ns-publics *ns*))

19:24 amalloy: brehaut: he probably wouldn't want to write his own, since he'd keep deleting it

19:25 brehaut: amalloy: it doesnt have to live in the same namespace :P

19:26 amalloy: aha, but who ever goes on a rampage deleting *just one* namespace? once you get started it's just so exhilarating you wind up with a totally empty jvm

19:27 brehaut: this must be an emacs users affliction :P

19:29 mjg123: technomancy, unzip classpath->dir working now, thanks

19:44 mabes: how do you kill the swank process that 'clojure-jack-in' creates? killing the slime REPL didn't seem to do it...

19:54 technomancy: mabes: *swank* buffer

19:55 mabes: technomancy: ah, right.. thanks! I probably would have figured that out if I didn't have a million buffers open :)

19:59 cark: technomancy : did anyone bother you already with swank + clojure 1.3 under windows showing "^M" behind any output in emacs ?

20:00 technomancy: cark: I don't think so.

20:00 cark: well you know that clojure changed the way it outputs newline characters in 1.3

20:00 i was able to quickfix this by changing the value of system-newline in my user.clj

20:01 but the real problem is in swank i guess

20:01 that would not be a problem at all, having ^M behind each output in the repl

20:01 but it messes also with the auto-complete-mode

20:02 making it unable to show quick help

20:02 anyways just to let you know, i personally am good with it

20:05 technomancy: ok, well let me know if you have a patch

20:05 cark: i will not dive into swank =)

21:47 shep-home: technomancy: trying to run tests from clojure-test-mode, I just started getting "error in process filter: if: Wrong number of arguments: nil, 11"

21:47 what have I done wrong?

23:04 Zolrath: I'm trying to download files using clojure.java.io but it seems to crap out and leave the end of most images incomplete.

23:04 technomancy: shep-home: where'd you get it?

23:04 Zolrath: (io/copy (io/input-stream url) (io/output-stream desination)) seems like it shouuld work and it almost does.

23:07 Seems that it works fine on some domains but other domains every single image will have the bottom half blacked out

23:07 amalloy: Zolrath: fwiw, i had to do that myself like half an hour ago, and that worked

23:07 though actually i created the output stream myself using java interop, because i don't use c.j.io very much and forgot

23:14 Zolrath: amalloy: Hm that makes me even more confused then.

23:15 amalloy: Zolrath: https://github.com/flatland/classlojure/blob/d63c49/test/classlojure_test.clj#L5 is my relevant snippet

23:25 Zolrath: amalloy: Thanks. Oddly enough that method is getting the missing part of the image that the seeming similar method I used fails to get

23:29 srid: can clojure.java.io be used to convert a string into an input stream? reading the docs tell me not. or must I continue using: (-> "foo" (.getBytes) (ByteArrayInputStream.)) ?

23:32 Zolrath: amalloy: it would appear the output-stream in clojure.java.io is to blame, or at least my usage of it. With your direct call to java.io.FileOutputSream it works perfectly but if I use the io/output-stream I lose the tail end of the images.

23:35 amalloy: srid: no. in general you shouldn't be trying to treat a string as a sequence of bytes, because it's a sequence of characters

23:35 and depending on the active character encoding, a given sequence of bytes could be interpreted in zillions of different ways

Logging service provided by n01se.net