#clojure logs

2010-04-12

00:14asimjalisSuppose I wanted to represent Java as sexp, what would be a good notation for this? Are there any examples?
00:15asimjalisI want the notation to encompass all possible Java programs.
02:38Licenser_morning
03:12asimjalisGood morning Licenser.
03:13asimjalisWhat's a way to change *compile-path* before calling compile?
03:15asimjalis(binding)
03:15asimjalis"binding" ?
03:16hiredman,(doc binding)
03:16clojurebot"([bindings & body]); binding => var-symbol init-expr Creates new bindings for the (already-existing) vars, with the supplied initial values, executes the exprs in an implicit do, then re-establishes the bindings that existed before. The new bindings are made in parallel (unlike let); all init-exprs are evaluated before the vars are bound to their new values."
03:33Licenser_(doc compile)
03:33clojurebot"([lib]); Compiles the namespace named by the symbol lib into a set of classfiles. The source for the lib must be in a proper classpath-relative directory. The output files will go into the directory specified by *compile-path*, and that directory too must be in the classpath."
03:33Licenser_hi Raynes
03:33RaynesLicenser: Hello.
03:34Licenser_I've played with the . replacement earlyer
03:35dcnstrct,(org.apache.commons.codec.binary.Base64/encodeBase64String "foo")
03:35clojurebotjava.lang.ClassNotFoundException: org.apache.commons.codec.binary.Base64
03:36RaynesLicenser: Any progress?
03:36Licenser_Raynes: yes and no :P it's not trivial
03:37Licenser_I managed to replace all dot's with something else but it now does not like the function names since it tries to resolve them :P and I am not entirely sure how to quote them
03:37RaynesHehe.
03:40Licenser_sucks to be me :(
03:41TheBusbyany hints on how to use contrib's slurp* with Shift-JIS encoded HTML?
03:42Chousukehmmh.
03:42Chousuke~def slurp*
03:42clojurebotTitim gan éirí ort.
03:42Chousukemeh
03:42Chousukedoesn't it take an encoding parameter?
03:43TheBusbyahh, slurp does but slurp* doesn't
03:43TheBusbylooks like someone patched slurp https://code.google.com/p/clojure/issues/detail?id=121
03:46dcnstrctslurp and spit are awesome names btw.. I hope they don't get changed to something boring.
03:46ChousukeI wonder if GC already has an API to extract tickets from the issue tracker :/
03:46Chousukethe ticket to move them over to assembla is still open :P
03:47bozhidarwhile on the topic of files I was wondering what is the idiomatic way in clojure to work with binary records
03:47Chousukedcnstrct: They also imply (correctly) that they're a bit crude :)
03:47bozhidarI can easily port my existing Java code, but it seems so ugly...
03:48dcnstrctb
03:48dcnstrcterr
03:49dcnstrctctrl-x b in the wrong terminal.. *sigh*
03:49dcnstrctif only there was a way to get irssi to run in emacs...
03:50hoeckbozhidar: what is your java code using? nio?
03:50bozhidarhoeck: yes
03:51bozhidarI have a set of null separated binary records
03:51hoeckI guess its ok to use nio then
03:51bozhidarthat I extract and decode, since they are actually text
03:52hoeckyou could also use seqs of bytes, but I fear that this would be horribly inefficient
03:52bozhidarI was just wondering is there is some more clojurish may to do it
03:52bozhidarwell efficiency is not that of a concern
03:53hoeckI'm currently trying to parse the mysql binary log in clojure, and I'm using nio
03:53bozhidarI'm teaching free programming courses at the technical university of sofia
03:53bozhidarand develop some small open source projects with my students
03:53bozhidarto give a feel of what real development is all about
03:54bozhidarand this is part of one of those projects
03:54bozhidarelegance is more important at this point for me, than efficiency
03:54bozhidarhoeck: thanks for the input, I guess I'll stick to nio
03:54hoeckwhen translating your code from java to clojure, you should try to write most functions in a immutable way, e.g. not using .put on your input-buffer, or incrementing counters
03:55bozhidarhoeck: I'm trying, but many years of C/C++/Java haven't done much good to my functional thinking
03:56hoeck: ), well, its never too late to start over
03:57Chousukeif you need to do parsing, you might want to take a look at fnparse for inspiration. maybe
03:57hoeckbozhidar: but even writing functional code in c helps understanding the code and makes it more elegant
03:57ChousukeI think I saw a DSL library for parsing binary data into data structures somewhere too
03:58bozhidarhoeck: when you're mostly working on business or "enterprise" projects the code you typically write all day is - set something/ get something
03:58bozhidarthere is not a lot of room for creativity...
03:58hoeckbozhidar: and if elegance is that important, and you don't need nio specifc things like .position or .order, then building a lazy seq of bytes and parse that might be an elegant solution
03:59hoeckI know :/
04:01bozhidarhoeck: I'm thinking the same thing about the lazy byte seq
04:02bozhidarthat way I'd only need the decoder from nio
04:02bozhidarand code(although slow) will probably be much more clojurish
04:02hiredman, (read-string (binding [*print-dup* true] (pr-str (struct (create-struct :a :b) 1 2))))
04:02clojurebotjava.lang.RuntimeException: java.lang.Exception: EvalReader not allowed when *read-eval* is false.
04:02hiredmanARGH
04:02hiredmannot even the exception I was looking for
04:06hiredman,(binding [*print-dup* true] (pr-str (struct (create-struct :a :b) 1 2)))
04:06clojurebot"#=(clojure.lang.PersistentStructMap/create {:a 1, :b 2})"
04:06hiredmanand structmap has no such method as create
04:37Licenser_why can't I use binding to change the ns? I try to do: (binding [*ns* (create-ns 'bla)] (def a 1)) but it ain't working :(
04:37Licenser_ah found it
04:58caljunioranyone around who tried building couverjure recently?
05:00caljuniorls
05:01caljuniorls
05:02caljunioroh crap
05:21Rayneskzar: ping
05:32RaynesI feel so special. Who else here had grilled steak and sausage for breakfast?
06:54licoresseI am looking for an extended example of how to user the new defprotocl in 1.2
07:27hamzac.c.logging docs say, "Unless otherwise specified, the current namespace is used" but how can i tell it to use a different namespace so that i can get rid of #<core$ns_name__5578 clojure.core$ns_name... style junk from the logs.
07:35sergey_miryanovhi all!
07:36sergey_miryanovi have a problem with mvn clojure:repl under windows. somebody can help me?
07:38sergey_miryanovwhen i type symbols nothing prints on screen, after i press enter typed string prints on screen
07:38sergey_miryanovit's really annoing
07:39AWizzArdHi rhickey.
07:39rhickeyhi
07:40rhickeyGreat phrase from http://twitter.com/therealadam - "Clojure's novel simplicity vs. Scala's familiar complexity"
07:41rhickeyoriginally here: http://twitter.com/therealadam/statuses/12001324496
07:48Licenser_greetings rhickey
07:49rhickeyhi
08:02Licenser_the more I can really code in clojure the nicer it looks
08:20chouseryeah, I saw that tweet. I think it overstates scala's familiarity (thinking of traits, auto-casting, type system details, etc.)
08:21rhickeywell, is it the features that are familiar, the syntax, or the complexity?
08:30chouserthe features and syntax are both superficially familiar I suppose
08:35rhickeyI think the complexity is familiar too, if unrecognized. People just grok the usage rules of one feature at a time and fail to see the accretion of complexity
08:38mfexwhich of these is more clojure-ish? (apply conj '[a b] '[c d]) or (vec (concat '[a b] '[c d]))
08:39chouserthat's a good point, and applies to features and syntax as well. no whole-hog new syntax, immutable locals, etc. as with clojure.
08:39rhickeymfex: neither: (into '[a b] '[c d])
08:40chouserand to be fair, scala led me if none too gently toward the immutable locals, lazy seqs (streams), and functional style.
08:40mfexrhickey: even better, thanks
08:41rhickeyI love the quote, very succinct capturing of the issues
08:42rhickeyand once you overcome the novelty, you are left with simplicity, while in the other case you get the familiarity right away but are left with the complexity for good
08:43chouseryup
08:43rhickeyobviously anything so pithy must oversimplify things a bit
08:44chouserI like the framing of it too -- as an observation of the ongoing choices of programmers
08:45rhickeychouser: yes, and I think no matter what is said, this true nature of the thing will determine the outcome
08:45rhickeybecause you can't really talk someone into loving a programming language
08:46chouservery little of Clojure seems novel anymore. It's actually a bit boring.
08:46chouserperhaps this book is burning me out a little. heh.
08:46rhickeytalk only gets people to try things
08:46rhickeyvery little of Clojure is novel, depending on one's background
08:47AWizzArdYes. A friend who did Mozart a long time understood basically all concepts extremly fast.
08:47AWizzArdThus, he found Clojure simple to use :)
08:49chouserrhickey: did you see my idea for a horrible hack on proxy ctors?
08:50rhickeychouser: no[e
08:50rhickeynope
08:50chouserclojure-dev -- I'll get you a link.
08:51chouserbecause I just *know* you want to see my idea for a horrible hack. :-)
08:52chousergroups.google.com/group/clojure-dev/browse_thread/thread/8ffac5eac2e1f97a
08:53chouserhttp://groups.google.com/group/clojure-dev/browse_thread/thread/8ffac5eac2e1f97a
08:58rhickeychouser: but the problem still remains, if you needed access to any data, since that won't be there yet either
08:59rhickeyi.e. its fields are uninitialized, maybe a non-issue as each method impl is its own closure
09:00rhickeybut I'd hate to introduce behavior (apparent access to closed-overs) that we couldn't support in reify
09:01rhickeyand we can't, since its closed overs will be uninitialized fields
09:01rhickey(should reify ever support bases with ctors)
09:01rhickeysorry I didn't reply earlier - I had seen it but blocked it out in horror
09:01rhickey:)
09:08rhickeyI'm ok with saying - sorry, the evil class made you use gen-class
09:32chouserrhickey: heh, yeah, ok.
10:07slyphonso if i want to write a java class that implements IMeta, er, how do i do that?
10:13dnolenhmm, what is the idiomatic way to reset the value of an agent?
10:13stuartsierradnolen: (send the-agent (constantly "foo"))
10:14dnolenstuartsierra: thx
10:19chouserslyphon: you want to write it in Java!?
10:20esjgents: are protocols meant to support variadics ? Mine are binding & as if it was a variable !
10:24chouseresj: no support for variadics in protocols (yet)
10:24slyphonchouser: i'm just writing a custom exception class
10:24chouserslyphon: have you looked at clojure.contrib.condition ?
10:24slyphonyeah, i'm running into trouble with the macro expansion
10:25chouseroh, ok.
10:25esjchouser: Thanks. Any idea on a timeframe for that ?
10:25chouseresj: haven't heard any mentioned, no.
10:26slyphonweird stuff, like java NPE in LispReader
10:26slyphonand other stuff like trying to come up with a "general catch-all"
10:26slyphonhttps://gist.github.com/9e189a0fb0b57683a778
10:26esjbummer. Its pretty central to a lot of stuff: (populate-type x & xs) etc etc
10:29chouseresj: rhickey is here, so perhaps he'll be inspired and have that fixed by lunchtime. :-)
10:30rhickeychouser: have what fixed?
10:30chouserrhickey: add support for variadics to protocols
10:31chouser"add" not "fix"
10:32rhickeyah
10:33rhickeyprobably not, but you are only a wrapper function way from having an API that is variadic. Remeber, protocols are a minimal spec for implementations, not a totality of an API for users
10:34rhickeyaway
10:34rhickey(defn foo [x & xs] (do-foo x xs)) (defprotocol Foo (do-foo [x xs]))
10:37dnolenif you call shutdown-agents how do you start things back up again?
10:44chouserdnolen: don't call shutdown-agents until you're done. :-)
10:50dnolenhmm when driving an animation if you're going to use agent I suppose you have to use send-off and Thread sleep (and hard code a value based on the expected framerate), or is there a better way?
10:50stuartsierradnolen: maybe a timer?
10:51dnolenstuartsierra: the timer that calls send-off on the agents ?
10:54chouserdnolen: There's an executor for calling functions at regular intervals
10:54dnolenchouser: in Clojure?
10:54stuartsierradnolen: I was thinking a timer that observes the state of the agent at a fixed framerate and draws the animation
10:55dnolenstuartsierra: sadly the agent can't just keep ploughing through, the calculations take too long.
10:55chouserjava.util.concurrent.Executors/newSingleThreadScheduledExecutor
10:55chouseris what I was thinking
10:55dnolenagent -> agents
10:56stuartsierradnolen: What I mean is, do the calculations in the agent actions, and draw your animation in a separate thread.
10:57dnolenstuartsierra: that's what I'm doing.
10:57dnolenbut I need to throttle the agents because otherwise the actions pile up really fast
10:58chouserand I'm suggesting that instead of having an agent that calls itself with Thread/sleep, you might consider a ScheduledExecutor to call a fn at regular intervals for you
10:59dnolenchouser: hmm. what I'd really like to do is stick with agents but have some way to calculate the thread sleep based on how long the last action took to complete.
11:00AWizzArdIs it possible to have a FileInputStream or something like that which acts on a part of a file, for example marked by a byte offset and byte length?
11:01stuartsierradnolen: If you (send *agent* action) within an agent action, it won't get sent until the current action completes. Is that what you want?
11:01Licenser,(throw RuntimeException "Ruuuuuuun Forest Ruuuuuu!")
11:01clojurebotjava.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.Throwable
11:01Licenser,(throw (RuntimeException. "Ruuuuuuun Forest Ruuuuuu!"))
11:01clojurebotjava.lang.RuntimeException: Ruuuuuuun Forest Ruuuuuu!
11:01dnolenstuartsierra: reall? I'm actually using send-off does that apply for send-off as well?
11:01stuartsierradunon
11:01stuartsierradunno
11:02S11001001dnolen: it does, the only difference is that they use different thread pools
11:04dnolenhmm, (send *agent* action) causes poor animation, probably from coordination overhead?
11:05S11001001are you relying on the order of action execution?
11:05stuartsierradnolen: still confused: are you drawing the animation in the action function?
11:05dnolenstuartsierra: no
11:05stuartsierraok
11:07dnolenS11001001: I don't think so. The agents update the "boids" and the render loop reads out the snapshots and renders those.
11:07dnolenstuartsierra: hmm, it doesn't look like (send *agent* action) waits
11:07dnolenthat's the problem.
11:07dnoleneven when I stopped my render loop, the agents kept burning on through their piled up actions
11:08chouserdoesn't wait for what?
11:08dnolenchouser: stuartsierra above implied that the action doesn't get sent until the current action complete if you use (send *agent* action)
11:08stuartsierrano no
11:09stuartsierraIf you send an action WITHIN another action, it waits until the current action finishes.
11:09chouserif you do a 'send' or 'send-off' in an action, those don't get queued until the action you're in is done.
11:09dnolenstuartsierra: ahh I understand. Which explains the crazy pileup of actions and the reason I need Thread/sleep. I don't want the agent action queue to build up like that.
11:10stuartsierraSo use the action itself to send the next action.
11:11dnolenstuartsierra: I'm getting confused now that's what I'm doing, http://gist.github.com/363662, you can just look at the bottom.
11:14stuartsierraI see. I'm not sure that send-off is the right thing to use there.
11:14stuartsierraPlain "send" should work.
11:15dnolenstuartsierra: the animation suffers with send, actions pile up and it eventually slows to a crawl.
11:15esjchouser, rhickey: sorry for vanishing: work called. I'll look at that suggestion, thanks.
11:15stuartsierradnolen: That shouldn't happen. There's something else going on.
11:15triyo"Joy of Clojure" has a quote in sec 4.1.2: "It is better to have 100 functions operate on one data abstraction than 10 functions on 10 data structures. -- Rich Hickey". I thought this was a Alan J. Perlis quote. ;-)
11:16rhickeytriyo: It is a variant of Perlis, who said one data structure
11:17dnolenstuartsierra: not sure what that would be, the send part of this code is tiny. Without the send stuff this code works perfectly and the update/renderloop takes about 14-18ms
11:17triyooh I see "one data abstraction"
11:18esjtriyo: the chapter starts with the Perlis quote.
11:18stuartsierradnolen: huh, I dunno, then
11:18stuartsierrasorry
11:35dnolensetting up the agents on a separate thread with future and an infinite loop around send/await seems to be the simplest approach in my case, I can get rid of the thread sleep this way.
11:39hiredmandnolen: is there some reason you are using agents at all?
11:39AWizzArdBtw, what happened with the deftype issue? Are there now two deftypes? How are they called? deftype and defrecord?
11:39dnolenhiredman: seemed the easiest way to take advantage of multiple cpus
11:41hiredmanare you using the stm at all?
11:41dnolenhiredman: not at all.
11:41hiredmanI would look at using queues and executors directly
11:42chouserAWizzArd: nothing has changed yet. I think the current plan is 'defrecord'
11:43AWizzArdAnd defrecord will be what currently deftype is yes? But with implicit support for “:as this” and without having to explicitly declare clojure.lang.IPersistentMap?
11:43dnolenperhaps, but I was looking for a simple solution. what I can up with only required me to change a small portion of my program.
11:56AWizzArdWould it make sense to let all defrecords be java.io.Serializable?
11:56cemerickAWizzArd: I've prodded Rich on this before. I'm hoping.
11:57cemerickObviously not for long- or even medium-term storage, but to make stuff like session stores and such work reasonably.
12:03AWizzArdwhy not for long-term storage?
12:07LicenserAWizzArd: I guess becase serialisation might change over versions
12:07cemerickAWizzArd: because classnames will almost certainly change across versions.
12:08AWizzArdAh ok
12:08LicenserI personally prefare a 'neutral' format for storage, json, yaml, (if it has to be) xml or somethin that isn't directly cuppled with the code
12:09AWizzArdEven then the class will have to be saved.
12:10AWizzArdAnd that could be (deftype Foo [a b c]) (class (Foo 10 20 30)) ==> namespace.Foo__14052
12:10AWizzArdbut also with some other number
12:10cemerickthis is what print-dup is intended to resolve
12:10LicenserAWizzArd: depends some kind of data structure
12:16jfieldswhat's the best way to convert from a string to a double?
12:17chouser,(Double/valueOf "5.1")
12:17clojurebot5.1
12:17dakronewhat's the difference between that and (Double/parseDouble "23")
12:17jfieldsI'm actually trying to (int) Double.parseDouble(element.getAttribute("Quantity").getValue()) - and I don't care about hard casting from double to int
12:17dakrone?
12:17jfieldscool, just wasn't sure if there was a nice clojure wrapper
12:17chouser,(Integer/valueOf "5")
12:17clojurebot5
12:18jfields,(Integer/valueOf "5.1")
12:18clojurebotjava.lang.NumberFormatException: For input string: "5.1"
12:18chouser,(read-string "5.0")
12:18clojurebot5.0
12:18jfieldsinteresting, would you recommend read-string chouser?
12:18chouser,(map read-string (.split #" " "5.0 5 5M 2/3 foo"))
12:18clojurebot(5.0 5 5M 2/3 foo)
12:19chouser,(map #(class read-string %) (.split #" " "5.0 5 5M 2/3 foo"))
12:19clojurebotjava.lang.IllegalArgumentException: Wrong number of args passed to: core$class
12:19chouser,(map (comp class read-string) (.split #" " "5.0 5 5M 2/3 foo"))
12:19clojurebot(java.lang.Double java.lang.Integer java.math.BigDecimal clojure.lang.Ratio clojure.lang.Symbol)
12:19jfields,(Integer/parseInt "5.1")
12:19clojurebotjava.lang.NumberFormatException: For input string: "5.1"
12:20chouserjfields: depends on the context. If you always want an Integer and it's from an untrusted source, I'd use Integer/valueOf
12:20jfieldschouser: cool, thanks.
12:21chouserif you want to allow a different radix, different types, etc. then read-string is an interesting option.
12:21chouser,(read-string "2r010011000101")
12:21clojurebot1221
12:22jfieldsit's coming from a trusted source that will always send doubles, so I don't think there's really much difference
12:23jfieldswhat about converting from double to int in clojure, any recommendations?
12:23jfields,(Math/round 5.1)
12:23clojurebot5
12:23chouserright, just the Java stuff.
12:23jfieldschouser: thanks.
12:23chouserwell, I guess if you've got a Double you can use (int ...)
12:24cemerick,(int 5.9)
12:24clojurebot5
12:45vegaidoes that clojurebot work inside some kind of a sandbox?
12:45chouseryep
12:46chouser,(System/exit 1)
12:46clojurebotjava.security.AccessControlException: access denied (java.lang.RuntimePermission exitVM.1)
12:47vegainice.
12:49Raynes$(System/exit 1)
12:49sexpbot1
12:49RaynesUgh.
12:49RaynesI've screwed stuff up again.
12:50vegaihuh?
12:50vegai$(+ 1 1)
12:50sexpbot1
12:50RaynesI've screwed stuff up should suffice as an explanation.
12:50vegai;)
12:50vegai,(+ 1 1)
12:50clojurebot2
12:50vegaiah, I'm still sane
12:50vegairelatively
12:54vegaiit's hard to appreciate too much the fact that a language's name is unique
12:58Raynes$(+ 2 2)
12:58sexpbot4
12:58Raynes$(System/exit 1)
12:58sexpbotUnable to resolve symbol: S in this context
12:58RaynesWell, it seemed fixed.
12:59RaynesOh, I see.
13:00Raynes$(System/exit 1)
13:00sexpbotUnable to resolve symbol: S in this context
13:00RaynesOkay, time to go into debug mode. :|
13:03RaynesBy golly, I've fixed it.
13:03Raynes$(System/exit 1)
13:03sexpbotDENIED!
13:03vegai$(+ 1 1)
13:03sexpbot2
13:03vegaifunny that breaking it caused that to evaluate to 1
13:03RaynesIt was tricky, because the $( command requires a bit of special behavior.
13:03vegaior was everything evaling to 1?
13:04Raynesvegai: I'm not sure exactly how it was parsing the expression, but it was only evaling 1 because it was the last part.
13:04Raynes$eval 1
13:04sexpbot1
13:05Raynes$eval 1)
13:05sexpbot1
13:05Raynesvegai: It was seeing it like this: System/exit 1), so it was only evaluating 1. :>
13:06Raynes$eval System/exit 1)
13:06sexpbotUnable to find static field: exit in class java.lang.System
13:06RaynesOr not. It must not have seen the first part at all.
13:06RaynesOdd.
13:07drewrRaynes: /j ##test
13:07Raynesdrewr: I'm not testing the bot here.
13:07RaynesI was demonstrating what I think was wrong because he asked. If that bothered anybody, they could have said so. :)
13:08RaynesThe bot is also in #clojure-casual for longer discussions or playtime.
13:12RaynesEverytime I mention #clojure-casual here, at least 2 people do a quick spy mission to see how many people are there. :>
13:14dakronehow many people are there? :P
13:15Raynes7
13:15RaynesWell, 6.
13:15RaynesIt's a young channel.
13:15RaynesBut it's a safe haven for when people like drewr and Lau Jensen ruin all your fun. :p
13:36LauJensenHey team
13:36dakronehey Lau
13:39RaynesLauJensen: Hai.
13:39RaynesLauJensen: I was just talking about you.
13:39Raynes<Raynes> But it's a safe haven for when people like drewr and Lau Jensen ruin all your fun. :p
13:40LauJensenWhat were you talking about? There's no safe haven from me and drewr ...
13:40Raynes#clojure-casual
13:41LauJensenah
13:57chouser,(map inc (range 5))
13:57clojurebot(1 2 3 4 5)
13:57chouser,(binding [inc dec] (map inc (range 5)))
13:57clojurebot(-1 0 1 2 3)
13:57chouser,(binding [inc dec] (pmap inc (range 5)))
13:57clojurebot(-1 0 1 2 3)
13:57chouserwhy!?
13:58chousershouldn't that last one return (1 2 3 4 5) again?
13:58hiredmanpmap is eager/lazy
13:58cemerickchouser: no
13:58chouserbut it still does everything in other threads, doesn't it?
13:59chouserwhere inc should no longer have its thread-local binding to dec
14:00chouseroh... inc is dereferenced on the outside
14:00chouserpmap only sees the actual fn, not the var.
14:00chouserok. I can feel my sanity returning.
14:00cemerickchouser: welcome back :-)
14:00chouseroh, you're here, are you? :-)
14:01opqdonut,(binding [inc dec] (pmap (fn [x] (inc x)) (range 5)))
14:01clojurebot(1 2 3 4 5)
14:01opqdonutnow the deref happens in each thread
14:01cemerickoftentimes.
14:01chouserright. thanks.
14:01chouserI just need to complicate my example a bit... :-/
14:02cemerickSomeone tell all the clojure library writers to use the version config they have at their disposal, and stop using 1.0.0-SNAPSHOT.
14:03technomancypeople don't actually use clojure-http-client, do they? =)
14:03ipostelniktechnomancy, why?
14:04The-Kennytechnomancy: I think I or one library I'm using use it somewhere
14:04Raynestechnomancy: I use clj-apache-http.
14:04Raynes:p
14:04technomancyjust because I don't use it myself, but I wrote it =)
14:05technomancyand it's stuck in 1.0.0-SNAPSHOT-land for that reason
14:05ipostelnikI think http.agent uses it
14:06ipostelnikbut I could be wrong
14:07cemericktechnomancy: I certainly wasn't calling out anyone in particular. I just think hardly anyone writing clojure libs is particularly aware of the consequences of their versions, nevermind SNAPSHOT. There are libs that have had the same version since pre-1.1, and yet been breaking APIs like crazy and moving to some rev of 1.2's HEAD, and etc etc.
14:08technomancyyeah, it's only when you work on larger projects that spend 30s+ per build just checking for unnecessary snapshots that you feel the poin
14:09technomancy*pain
14:09cemericknah, it's when you're using a different version of clojure than the lib author or when the lib breaks long-standing fn signatures that you feel the pain :-)
14:10technomancywell breaking long-standing fn signatures w/o bumping major version numbers isn't SNAPSHOT-specific; it's just sloppiness IMHO.
14:10technomancybut yeah, yuck
14:11cemerickwell, one is ostensibly never supposed to republish any particular non-snapshot version, but yeah
14:11cemerickand most repo managers prohibit it by default
14:12technomancybreaking in bugfix or point releases is what I'm thinking of
14:12cemericksure
14:35zakwilson,(rest "foo")
14:36clojurebot(\o \o)
14:36zakwilson,(str (rest "foo"))
14:36clojurebot"(\\o \\o)"
14:36zakwilsonAnybody know how to get what I want? (that being: "oo")
14:37zakwilsonNevermind. subs does it.
14:38The-Kennyzakwilson: Yeah, either .substr, something in c.c.str-utils2 or (apply str (rest "foo"))
14:38The-Kenny.substr is propably the best method
14:39carkh,(apply str (rest "foo"))
14:39clojurebot"oo"
14:39chouser(subs "foo" 1)
14:39chouser,(subs "foo" 1)
14:40clojurebot"oo"
14:43carkhi like (rest "foo") it returns a nice little face =P
14:45chouser,(symbol (str \\ \o) "")
14:45clojurebot\o/
14:45carkhhaha awesome
14:45The-KennyOo, I didn't knew about subs
14:48The-Kennychouser: Hah, that's genius
14:49technomancypet peeve: subs doesn't let you count from the end using negative offsets
15:01chouser,(list (keyword "-"))
15:01clojurebot(:-)
15:19stuartsierraWhat do you do about "Invalid method Code length 68926"?
15:19LauJensenM-x apropos Invalid method Code
15:20stuartsierraI know what it means; I want to know if there's a way to ignore it.
15:22stuartsierraIt's a JVM limitation, so probably not.
15:23chousersplit it up into multiple funcitons I suppose
15:24stuartsierrathis is metacode
15:24scottjstuartsierra: do you have a bunch of data you can put in its own file and read in?
15:24stuartsierrait's a big macro expression
15:24stuartsierraI can split it up, but less elegantly
15:24chouserwrite a macro that splits it up into multiple functions. :-)
15:24stuartsierraIt's already a macro.
15:25stuartsierraI think the problem is the macro is one giant expression: it fails at the compilation stage.
15:25chouserI'm just guessing, but if the problem is the amount of code inlined in a function, a closure should be able to pull out a chunk of it without losing your lexical context.
15:26chouseris it like (do a b c ... zzy zzz)?
15:26stuartsierrano
15:26chouseror more nested? or what?
15:26stuartsierrait's (describe *ns* ....every spec in this namespace...)
15:27stuartsierraI don't have to write it that way, but it's convenient.
15:27chouserbut what does that expand to?
15:28stuartsierra(alter-meta! *ns* assoc :spec #:TestContainer(:children [...every spec in this namespace...]))
15:28stuartsierraThe whole file is one big expression: that's where it's choking.
15:30stuartsierraIf I define all the specs (unit tests) within one expression, I can reload the namespace without any old specs left hanging around.
15:30chouserwhat if 'describe' expanded to (do (alter-meta! *ns* assoc :spec #:TestContainer{}) (alter-meta! *ns* update-in [:spec :children] conj spec1) (alter-meta! ... spec2) ...) ?
15:31chouserdunno if that would help or not, but that's the kind of thing I would try
15:31stuartsierraThe compiler still has to generate one lambda to evaluate that, doesn't it?
15:32chouserpossibly. but if it can be broken down like that, then you're back to (do a b c d ... zzz)
15:32chouser...and then maybe you can do (do (#(a b c d)) (#(e f g h)) ... (#(zzz))) or something
15:40stuartsierradoes 'do' compile in a special way?
15:44stuartsierraok, wrapping macroexpansions in ((fn [] ...)) avoids the error
15:46stuartsierrathanks
15:50zkimIs there a way to cons onto the end of a vector other than assoc?
15:51kotarakzkim: conj
15:51kotarak,(conj [1 2] 3)
15:51clojurebot[1 2 3]
15:51zkimkotarak: ah, thanks
16:24chouser,(read-string (str (Exception. "foo")))
16:24clojurebotjava.lang.RuntimeException: java.lang.Exception: Invalid token: java.lang.Exception:
16:25chouserthat's just a weird-looking error.
16:25zkimlol
16:25chouserwe'll pretend I wasn't actually seeing that in my unit tests...
16:26zkimDidn't see nothin
16:35tomswI'd like to set a bunch of properties on a java object (an SWT Event) from a map. Is there an easy way?
16:36tomsw(set! (. obj prop) value) assumes that prop is a symbol whose name denotes the field to modify
16:36tomswwhereas in my case its value will be a symbol whose name etc.
16:37chouserthese are fields you want to set, not setters you want to call?
16:37tomswchouser: hello, yes
16:37tomswSWT Event has quite a few fields and no setter / getters
16:39tomswset! isn't what I expected it to be (a clojure macro) - maybe I'd be better off with reflection
16:39chouserbleh. you might do best to write your own macro
16:39tomswyup
16:39chouseryou want something like (set-many! obj prop1 val1, prop2 val2, ...) ?
16:41tomswbasically. I ended up with an Event factory with the various field names as keyword args, crap like (when keyCode (set! (. keyCode ev) keyCode))
16:41chouseroh, you said from a map
16:42chouserwill it always be a literal map? (set-many! obj {:prop1 val1, :prop2 val2}) or do you want to support (set-many! obj a-map)
16:42tomswwell that was the other thing, keyword args in Clojure seem to be used (func {:arg1 v1 :arg2 v2}) instead of (func :arg1 v1 :arg2 v2)
16:43chousernah, each is preferred by a different set of Clojurites.
16:43chouserI think rhickey is in the latter camp. :-)
16:43tomswi better find out how to do the latter because I'm in that camp too, CL baggage I suppose
16:44chouserif you do it the latter way, it's clear you can't just pass in a map at runtime, which can allow you to do some clever performance things at compile time.
16:46tomswwell a (set-many! obj :prop1 v1 etc) macro would be a lot easier to write than a (set-many! obj map) one
16:51tomswI suppose the (set-many! obj prop-val-map) version would have to use eval?
17:01StartsWithKtomsw http://paste.pocoo.org/show/201170/
17:04carkhStartsWithK: did you have any success with fuzzy matching of java methods in clojure-mode ?
17:04carkhor swank-clojure really
17:05StartsWithKi never used emacs
17:05StartsWithKwrong nick?
17:05carkhoh hum sorry .... must be someone else !
17:06carkhit was the-kenny =P
17:06carkhsecond word starts with k anyways
17:07The-Kennycarkh: Not really, sorry. I just played a bit around, nothing really serious.
17:07carkhno big deal, i was just curious
17:50esjexcuse me clojure-bot...
17:50esj,(rem (nth ((fn fibo
17:50esj ([]
17:50clojurebotEOF while reading
17:50esj (concat [0 1] (fibo 0 1)))
17:50esj ([a b]
17:50esj (let [n (+ a b)]
17:50esj (lazy-seq
17:50esj (cons n (fibo b n))))))) 1000000) 1000)
17:50esjhmm.... that won't save you for long...
17:51esj,(rem (nth ((fn fibo ([] (concat [0 1] (fibo 0 1))) ([a b] (let [n (+ a b)] (lazy-seq (cons n (fibo b n))))))) 1000000) 1000)
17:51clojurebotExecution Timed Out
17:51The-Kennyesj: You can query clojurebot. That won't spam this channel
17:51esjactually it was all leading to a question
17:51esjthat code shouldn't cause a Heap overflow
17:52esjaccording to http://groups.google.com/group/clojure/browse_thread/thread/57a12f1a0dab5e1b/cb3db6e6ac94092f?#cb3db6e6ac94092f
17:53esjbut it does on my machine. If I understand things, clojure should be GC'ing the seq as the calculation rolls along, but on my machine in getting a Heap overflow. What stupidity has trapped me this time ?
17:54carkhdo you have any idea on the size of the bigint you're making ?
17:55esjcarkh: what you're saying is that its a single number that's overflowing the heap ?!
17:56carkhhum looks like it isn't
17:56carkhit's working here
17:58Chousukenth shouldn't hold the head either I guess
17:58Chousuke,(nth (range 10000000) 10000)
17:58clojurebot10000
17:58carkhthos my java process is now 1.6gb =P
17:58Chousukehmm
17:58Chousuke,(indexed? (range 10))
17:58clojurebotjava.lang.Exception: Unable to resolve symbol: indexed? in this context
17:59Chousuke,(instance? (range 10) clojure.lang.Indexed)
17:59clojurebotjava.lang.ClassCastException: clojure.lang.LazySeq cannot be cast to java.lang.Class
17:59Chousuke,(instance? clojure.lang.Indexed (range 10))
17:59clojurebotfalse
17:59Chousukemeh
18:01esjcarkh: I guess your GC figure it didn't need to run, so hasn't yet.
18:01esjbut what's exercising me, is that mine should have, but couldn't, apparently.
18:03carkhdoes it work with the fib-naive2 that's a bit lower int he thread ?
18:06esjcarkh: that did work !
18:07esjso the number can be represented, but something in the lazy-seq is going awry
18:08carkh~def nth
18:09lancepantzcan anyone make out what is wrong with this route? (defroutes actions (POST (route-compile "/:id/:action" {:id #"\w+-\d+" :action #"\d+"}) [id action] "hi"))
18:10lancepantzi get symbol cannot be cast as charSequence
18:10lancepantzit works just fine in a repl with the clout function only, only breaks when i put it in the defroutes
18:20lancepantzlooks like that is a now fixed bug
19:16programblehow do i tell if, for example, :foo is in a seqence?
19:16programble[:foo :bar :baz] returns true
19:17programble[ :bar :baz] returns false
19:17arbscht,(.contains [:foo :bar :baz] :foo)
19:17clojurebottrue
19:17arbscht,(.contains [:bar :baz] :foo)
19:17clojurebotfalse
19:17arbschtthat's one way
19:17programbleah
19:17programblethanks
19:18programbleno more clojure-y way?
19:18arbschtthat is clojure-y -- clojure is a hosted language ;)
19:19technomancy(contains? (set my-vec))
19:19arbscht,(some #(= :foo %) [:foo :bar :baz])
19:19clojurebottrue
19:19arbschtand so on
19:20arbscht,(clojure.contrib.seq/includes? [:foo :bar :baz] :foo)
19:20clojurebotjava.lang.ClassNotFoundException: clojure.contrib.seq
19:21arbscht,(require 'clojure.contrib.seq)
19:21clojurebotjava.io.FileNotFoundException: Could not locate clojure/contrib/seq__init.class or clojure/contrib/seq.clj on classpath:
19:21arbschthrm
19:21arbschtanyway, that's neater than some, if you don't mind the dependency
19:24programbleurgh
19:24programbleclojure needs a re-split
19:25technomancyit's in contrib's str-utils, but yeah
19:25technomancyand regexes need to be callable =\
19:25programbleclojure.contrib.str-utils/re-split ?
19:26arbschtit's 'split' in the new string lib
19:30programbleeh, ill just use (.split #"regex" s)
19:31programblewas writing a function to collapse whitespace
19:31programble(defn collapse-whitespace [s] (->> s (.split #"\s+") seq (interpose " ") (apply str)))
19:32programbleit works
19:34tomojdo you think a better syntax could make this usable? https://gist.github.com/43e7d7d5248e6d639eea
19:35tomojI just don't like having to choose between -> and ->> :)
20:17SynrGhm. where do patches to the 'clj' script included in ClojureX go?
20:22cheezeyso how would i go about making a lexer in clojure? :p
20:22slyphonhrm
20:24cheezeyhrm =__= so like i would prefer it being recursive, or something ;x
20:24cheezeyi think most lexers are.. ?
20:24carkhyou mean a lexer lexer or a parser ?
20:24slyphongha
20:25carkhi mean, do you need a lexer specifically ?
20:26cheezeycarkh: lexer im fairly certain. tokens and stuff right? :P
20:26carkhwhat's the goal ?
20:26cheezeycarkh: lexing some maths. like 2+3+5
20:26slyphonmaths!
20:26carkhi'd go for a full blown parser =P
20:26carkhusing fnparse
20:27carkhhttp://github.com/joshua-choi/fnparse
20:27cheezeyhm.. well so there's no easy way of doing this without the library?
20:28carkha lexer will only go to a point
20:28cheezeywell i mean i think i need a lexer eventually so that's why i'd like to learn it :o
20:28carkhthere is a hierarchy in a math expression, a lexer won't proide you with that
20:28carkhprovide*
20:28cheezeycarkh: yeah i know. the parser will do that portion =XXX
20:28cheezeyso future question: how do i write a parser LoL
20:29carkhthat second question, there are book written about it
20:29carkhbooksss
20:29slyphonthe dragon!
20:29slyphonbeware the dragon!
20:29cheezeycarkh: i mean in clojure =_=
20:29slyphonthe underlying principles are the same
20:29cheezeysorry im still new to functional so :\
20:29carkhwell, even if you want to do it yourself, i'd skip the lexer part and go directly for a recursive descent parser
20:29carkhthat's the easier to do
20:30cheezeyi just dont know if im missing some command that would simplify it
20:31carkhbut it's a lot of work with lots of edge cases, way easier to use an existing library
20:33zakwilsonShould (clojure.contrib.duck-streams/spit "foo" a-map) produce output readable with (read-string (slurp "foo"))? I'm having a problem where the read throws "java.lang.Exception: Invalid token: :"
20:34carkhtry replacing a-map with (with-out-str (prn a-map))
20:35carkhor pr instead of prn
20:37carkh,(read-string (with-out-str (pr {:a "blah"})))
20:37clojurebot{:a "blah"}
20:38zakwilsonLooks usable. Let's see if it breaks when fed a 26,000 item map.
20:38carkhahwell then you should directly print to a stream
20:38carkhinstead of passing through a string representation
20:39zakwilsonI bought a machine with 4 gigs of RAM so I could properly abuse it!
20:39cheezeyLoL
20:41zakwilsonI'm just glad Clojure's maps are more space-efficient than Haskell's.
20:42carkhoh they are ?
20:44zakwilsonA map of keywords to ints seems to use less than half the space of a Data.IntMap of 32-bit hashes to ints.
20:44zakwilsonAnd a Data.Map String Int is even bigger.
20:44zakwilsonMap operations in Haskell are faster though.
20:46cheezeythis is probably a really dumb question but why can't i do (cond (true)(true))? o_O
20:46zakwilsonBecause true isn't a function.
20:47zakwilson,(cond true true)
20:47clojurebottrue
20:47cheezeyya i am dumb lulzzz
20:57TheBusbymy favorite error message;
20:57TheBusby,(let [count 5 mylist [1 2 3]] (count mylist))
20:57clojurebotjava.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn
20:58hiredmanwith invokedynamic you could inject the IFn interface into Number to name Numbers work like (0 [1]) => 1
20:59RaynesWould anybody find title-scraping of links useful? programble and I just added title scraping to sexpbot, but I didn't want to enable it here unless anybody thinks it might be useful.
20:59RaynesIt only scrapes the titles of a maximum of 3 links in a message.
21:01RaynesWell, I have to go. I'll check back on that.
21:03RaynesAs a quick example, I'll leave this here http://github.com
21:03sexpbotSecure source code hosting and collaborative development - GitHub
21:03zakwilson(with-open [wtr (BufferedWriter. (FileWriter. "foo"))] (.write wtr (with-out-str (pr a-map)))) results in an empty file. That's... not what I expected. Should I just get some sleep?
21:04zakwilsonOh, wait... no it doesn't. I was looking at the wrong file. That settles it. I SHOULD just get some sleep.
21:04scottjRaynes: I think that's very useful.
21:05_atoprobably want to turn it off for gists and pastebins and such though, that'd just get annoying fast
21:05scottjRaynes: I'd most like it on google groups and youtube links
21:13Raynes_ato: That would take a little redesigning, but turning it off for specific links is definitely doable. Good idea.
21:38slyphonargh
21:38slyphonvariadic macros are eating my brane
22:01webwandererhow do i get the index of a sequence i'm mapping through?
22:02tomojclojure.contrib.seq-utils/indexed I think
22:03webwanderercool
22:03tomoj,(for [[i x] (map vector [:foo :bar :baz] (iterate inc 0))] [i x])
22:03clojurebot([:foo 0] [:bar 1] [:baz 2])
22:28TheBusbyanyone have any experience using java's CookieManager to access website content that requires login?
22:46lancepantzis there a neater way to write this?: (-> blob (get 1) (get 2) (get "edges") (get 0) (get "to_id"))
22:50tomoj,(get-in [:foo [:bar :baz {"edges" [{"to_id" 10}]}]] [1 2 "edges" 0 "to_id"])
22:50clojurebot10
22:50tomojI'd be interested to hear how you're modeling graphs, if that's what you're doing
22:50lancepantzoh, perfect man
22:50tomojclojure style is to use keywords instead of strings
22:50tomoj:edges instead of "edges" I mean
22:51hiredmanto-id vs to_id
22:51lancepantzyeah, i do in most places, this is just a test thats loading a blob from sql
22:51tomojah
22:51lancepantzand this is my graph library: http://github.com/ninjudd/jiraph
22:51sexpbotninjudd's jiraph at master - GitHub
22:55tomojlancepantz: very interesting
22:55tomojthanks
23:07technomancyoh man... I saw a thread titled "removing parentheses" on the mailing list... I was sure it was going to be about "let's make clojure use indentation instead of parens so the newbies will love it like Python!"
23:07technomancywe're about overdue for that, aren't we?
23:07technomancyluckily it was about flattening nested lists
23:07kiraslol
23:08kirasalthough, now that you mention it...
23:08danlarkinbut... but.. everyone /knows/ the problem with lisp is the parens!
23:21technomancyclojurebot: botsmack is <reply>clojurebot evades successfully!
23:21clojurebotc'est bon!
23:22technomancythat way it'll randomly choose between the two, right?
23:22technomancy,botsmack
23:22clojurebotjava.lang.Exception: Unable to resolve symbol: botsmack in this context
23:22technomancy~botsmack
23:22clojurebotOwww!
23:22technomancy~botsmack
23:22clojurebotclojurebot evades successfully!
23:22technomancy~botsnack
23:22clojurebotthanks; that was delicious. (nom nom nom)
23:24kiraslol
23:25hugodwhat is the idiomatic way of going from {:a 1 :b 2} to [:a 1 :b 2] - (apply concat (seq {:a 1 :b 2})) ?
23:28carkhwhy the seq call ?
23:28carkh(apply concat {:a 1 :b 2})
23:28dnolen,(into (apply concat {:a 1 :b 2}))
23:28clojurebotjava.lang.IllegalArgumentException: Wrong number of args passed to: core$into
23:28dnolen,(into (apply concat {:a 1 :b 2})))
23:28clojurebotjava.lang.IllegalArgumentException: Wrong number of args passed to: core$into
23:28carkh,(mapcat identity {:a 1 :b 2})
23:28clojurebot(:a 1 :b 2)
23:28technomancy,(read-string (apply str (replace {\{ \[ \} \]} (pr-str {:a 1 :b 1}))))
23:28clojurebot[:a 1 :b 1]
23:28technomancy(just kidding)
23:28dnolen,(into [] (apply concat {:a 1 :b 2}))
23:28clojurebot[:a 1 :b 2]
23:28dnolenerge
23:29carkh,(vec (apply concat {:a 1 :b 2}))
23:29clojurebot[:a 1 :b 2]
23:29dnolendoes vec use transients?
23:30carkhi don't know, look at the source =P
23:30carkh~def vec
23:30carkhnot very telling
23:31dnolendoesn't look like it.
23:31dnoleni think (into [] ...) is the expected pattern for converting things back to vectors quickly
23:31hugodthanks all, I can go back to my glass of wine now
23:32technomancyas long as you haven't had enough to take my suggestion seriously =)
23:33hugodenough to have trouble typing it, even if I did
23:36technomancywhat exactly is the point of the cons class?
23:36technomancy~(list? (cons 1 (cons 2 nil)))
23:36clojurebotHuh?
23:36technomancy,(list? (cons 1 (cons 2 nil)))
23:36clojurebotfalse
23:36technomancy,(list? (cons 1 nil))
23:36clojurebottrue
23:36technomancythis boggles me
23:37hiredmanyou use cons to build lazy seqs
23:37technomancyit's also used in some other places
23:37technomancyif you call a macro inside a macro, some of the code comes through as conses instead of lists
23:38hiredmansure
23:38hiredmansyntax-quote tearing through things
23:39technomancyI guess all that to say: never use list?, because it will betray you
23:39technomancysince it doesn't return true for some kinds of lists
23:39technomancy(conses and lazy seqs)
23:39hiredman,(doc list?)
23:39clojurebot"([x]); Returns true if x implements IPersistentList"
23:40technomancysure, but conses and lazy seqs are both persistent lists
23:40technomancythey're just not Persistent Lists
23:40hiredman*shrug*
23:41technomancyseems like a leaky abstraction
23:42hiredman,(doc list?)
23:42clojurebot"([x]); Returns true if x implements IPersistentList"
23:43hiredmanIPersistentList is Counted
23:43hiredmanthey are not lazy
23:44technomancyI guess conses aren't counted either
23:45hiredmanright, and the tail of a cons maybe lazy or not
23:45technomancyI just can't think of any situation in which you'd care about IPersistentList over listiness
23:45technomancysince we've already got counted?
23:46hiredmanshrug*
23:47technomancyhiredman: dude, shrug* is for internal use only.
23:47dnolenis it possible to check if something is lazy?
23:47hiredmanhey, I having three conversations here, and I don't even have an stm
23:48jcowanHow can you be sure you don't?
23:48technomancydnolen: if it's a seq?, it's not counted?, and it's not a cons it might be lazy
23:48technomancyor it might be some crazy new seq somebody reified out of thin air
23:49jcowanHuh. The topic hasn't changed since *I* set it two years ago? Wow.
23:49hiredmanno ops
23:50tomojcoi ui doi jy
23:50tomojdidn't know you were involved
23:50technomancyjcowan: yeah, I think we've all been waiting for you to return =)
23:50jcowanI was back then. Haven't been for a long time, thinking about getting involved again.
23:50dnolenjcowan: it's a whole different world now.
23:51technomancydnolen: well, mostly. there's still no canonical shell script. =)
23:51technomancyother than that it's all rainbows and unicorn marshmallows though.
23:51technomancyoh, and people still get confused by contains? I guess.
23:52tomojI never hear people complaining about tail recursion
23:53jcowanPerhaps that will be my contribution, then. :-)
23:53tomojI wonder if it's bad that I never find myself wanting it
23:53technomancythere is a build of openjdk 7 that enables it IIRC
23:53technomancyif I were really bored I would try to hunt that down
23:53jcowanIt's a way of thinking. If you don't have it, you don't miss it.
23:54dnolenyou also have laziness which lets you do a whole other set of interesting recursive tricks.
23:54jcowanQuite so.
23:54jcowanAnd if you want both, then there's *shudder* Haskell.
23:55tomojhah
23:57technomancyok... riddle me this then: why does PersistentHashMap use Util.equals instead of Util.equiv
23:57technomancysince it looks like Util.equiv behaves sanely in the presence of longs vs ints, etc
23:57dnolenit's finally beginning to dawn on me the ridiculous power of persistent data structures + dynamic typing, now I want them everything.
23:57hiredmanbecause PHM implements j.u.Map
23:58technomancy,(clojure.lang.Util/equals 1 (long 1))
23:58dnoleneverything -> everywhere
23:58clojurebotfalse
23:58hiredmanand the contract for j.u.Map's .equals is not the same as Util.equiv
23:58technomancyouch
23:59technomancyhow can they fit so much awesome into such close proximity with so much bustedness?
23:59tomojwow
23:59technomancythe JVM is amazing
23:59tomojI never realized that