#clojure log - Aug 07 2012

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

0:32 Cr8: what's the current best option to get started playing with clojurescript?

0:33 emezeske: Cr8: In my heavily-biased opinion? https://github.com/emezeske/lein-cljsbuild

0:35 xeqi: +1 for lein-cljsbuild

0:36 Cr8: hm

0:38 i keep getting a blowup looking for clojure.instant when I try to use anything that does cljs

0:41 hmm

0:42 I seem to be getting clojure 1.3.0 even though my project.clj specifies 1.4.0

0:44 xeqi: can you paste a `lein deps :tree` and project.clj ?

0:46 jonasen: emezeske: ping

0:47 Cr8: figured it out

0:49 jonasen: emezeske: about schoolseatingcharts: Is it built on canvas or svg? Do you drag'n'drop seats onto the canvas, or are their positions/directions predefined?

1:00 uvtc: amalloy: ping?

1:00 amalloy: que pasa?

1:01 uvtc: earlier, re. casion's question, he wanted to "remove damage at cooldown". What does that mean in english?

1:01 I'm looking at your full example, but I don't see what "cooldown" is supposed to mean.

1:01 amalloy: oh, the phrase is nonsense. i was just guessing based on how games make sense

1:01 Peregrine: It's a game term.

1:01 amalloy: cooldown was "number of time units between attacks"

1:01 clojurebot: No entiendo

1:02 amalloy: Peregrine: yes, the word "cooldown" is well established. what it means in his sentence/program is not

1:02 uvtc: But each fighter has a "cooldown" value...

1:02 Like hp, or dmg...

1:02 amalloy: right, they attack at different speeds

1:03 uvtc: But in the example code, during each round, they each get to hit once... They fight in sync with eachother...

1:03 I think...

1:03 amalloy: no

1:04 not the code i provided, at least

1:04 uvtc: The :cooldown-remaining gets updated each round, but I'm not seeing the significance of it.

1:04 amalloy: okay, start by dividing time up into "ticks" of whatever unit cooldown is in

1:04 uvtc: Each round the fighters are updated: `a` gets hit by `b`, and vice versa. The 2-item list is returned by `fight-one-round`.

1:04 amalloy: oh, you're right, they do fight in sync

1:04 i got that wrong

1:05 i need to only subtract one of their hp units, while updating both of their cooldowns, to implement what i meant to do

1:07 uvtc: just updated gist with a fight-one-round that more accurately reflect what i meant

1:08 and, good, now b wins my a smaller margin, which makes sense because he attacks more slowly

1:09 uvtc: So, the fighters can have different "rates of attack"? Interesting.

1:09 amalloy: that's the most obvious guess at what he means by cooldown

1:10 uvtc: Will look at the code again. But `fight-one-round` still returns that vector of 2 updated fighters, so it appears to me that the fighters are still fighting in sync. Will look more closely though.

1:10 amalloy: it returns two fighters now, but only one of them changes hp (most of the time)

1:12 ekoontz: thanks to @cemerick for http://cemerick.com/2012/08/06/results-of-the-2012-state-of-clojure-survey/

1:22 amalloy: uvtc: you can see it more clearly if you switch (first (drop-while ...)) with (take-while ...), and give the fighters lower cooldowns (try 4 and 10 for a good example)

1:23 the fast guy gets in a few punches, then the slow guy gets one, and after a few rounds they both strike at the same time when they both hit zero

1:23 uvtc: amalloy: I can just fine how the `fight` function works.

1:23 I think.

1:23 amalloy: uvtc: i know, but making that change to fight makes fight-one-round easier to understand

1:24 uvtc: `fight` just drops rounds until it gets to one where a fighter has health < 0, then gives you the result.

1:24 In `fight-one-round`, in the `let`,

1:25 I see what `ticks` is: it's just the mininum of the fighter's :cooldown-remainings. Though I don't understand why it's named "ticks".

1:25 I see what `damage-dealt` is: it's just a function that takes a fighter and returns either his regular damage or else 0.

1:26 amalloy: "number of ticks till someone gets to attack". rather than simulating a tick at a time, i skip over the ticks when nothing is happening

1:26 you could have ticks always be 1, and it would work just fine but return more uninteresting intermediate results

1:32 uvtc: amalloy: I see that `tick` is a function that takes a fighter and returns an updated fighter. It either sets this fighter's :cooldown-remaining to its value of :cooldown, or else it sets it to its :cooldown-remaining minus the min ticks between the two fighters.

1:33 amalloy: "how long till his next attack after this one?"

1:35 uvtc: Is that the question, the answer of which is :cooldown-remaining?

1:35 amalloy: right

2:19 uvtc: amalloy: Thanks. Got it.

2:19 amalloy: diabolical.

2:20 TEttinger: anyone use Seesaw here? I can't figure out why my window is incredibly wide

2:20 amalloy: heh, it was a straightforward a solution as i could think of

2:20 TEttinger: I keep setting maximum-size and it doesn't seem to notice

2:20 amalloy: definitely room for improvement

2:21 uvtc: amalloy: would you mind if I blogged about it?

2:21 amalloy: go for it

2:21 why?

2:21 clojurebot: why not?

2:21 amalloy: die in a fire, clojurebot

2:22 uvtc: amalloy: Well, for one thing, because casion wanted to know how it worked. And for another, I think it's rather clever. :)

2:22 TEttinger: the window is roughly 1900 pixels wide, and I can't seem to find any place I set that

2:23 amalloy: cool. well, send me a link when you're done

2:23 maybe one of these days i'll get back into blogging

2:23 uvtc: amalloy: Will do. It's way past my bedtime. G'night.

2:30 TEttinger: also, I can't grow a section of the frame with a divider -- the left side of a split pane can shrink, but not grow. the right side is huge and consists of one widget.

2:39 figured it out; I was calling (pack!) and it reset my widgets to use their preferred sizes

3:17 ro_st: so i'm trying to get domina to work. when i cljsbuild, i get "clojure.lang.Compiler$CompilerException: java.lang.RuntimeException: No such var: cljs.compiler/resolve-var, compiling:(domina/macros.clj:13)"

3:18 no idea how to resolve this

3:18 anyone using domina successfully?

3:31 jballanc: just curious...what are people using for a generic Clojure REPL? (i.e. not associated with a specific project)

3:37 Raynes: `lein repl` works. I guess the light table playground could also be an option.

3:38 edmund_: lein swank and slime-connect from emacs is my default

3:38 Raynes: Cool people use nrepl.el now.

3:38 jballanc: ah ok...just realized that `lein repl` works outside of a project if I configure my profiles.clj correctly :)

3:38 gko: Are SLIME for Clojure and Common Lisp still walking on each other?

3:39 ejackson: Raynes: P'TAK !

3:39 Raynes: Yeah, but you don't have to use slime anymore.

3:39 jballanc: yeah, I'd use nrepl.el but you'll pry vi from my cold dead hands ;-)

3:39 Raynes: gko: Check out nrepl.el.

3:39 Keep your SLIME config safe.

3:40 gko: which nrepl.el ? technomancy, kingtim, emacsmirror, ... ?

3:43 ro_st: kingtim

3:45 gko: ro_st: OK, so this (nrepl.el) + clojure-mode is all I need for Clojure, no more SLIME from package?

3:45 ro_st: i've no idea. haven't jumped in yet. Raynes will know :-)

3:45 i think that's the case

3:46 backup your .emacs.d and give it a spin?

3:46 gko: (I meant, slime-repl 20100404 from package)

3:46 ro_st: i still don't know, sorry

3:47 gko: ok

4:03 ro_st: so, (some) will tell me if some elements appear in a collection or not. how can i check whether all elements appear in a collection?

4:03 use some and verify that the result of some's length matches the ingoing set?

4:08 every?

4:46 jballanc: ro_st: something like this:

4:46 ,(empty? (reduce (fn [l c] (disj l c)) (set (map char (range 97 123))) "the quick brown fox jumps over the lazy dog"))

4:46 clojurebot: true

4:47 jballanc: ,(empty? (reduce (fn [l c] (disj l c)) (set (map char (range 97 123))) "does not use the whole alphabet"))

4:47 clojurebot: false

4:47 ro_st: thanks jballanc

4:49 jballanc: you can loop/recur with the empty check inside if you expect your set to be much smaller than the collection you're checking

4:49 ro_st: it turns out that the logic for determing inclusion differs from item to item, so my approach has to be a little different

4:50 determining*

4:52 clgv: ,(->> "does not use the whole alphabet" (map char) set (= (->> (range 97 123) (map char) set)))

4:52 clojurebot: false

4:53 clgv: ,(letfn [(char-set [c] (->> c (map char) set))] (= (char-set "does not use the whole alphabet") (char-set (range 97 123))))

4:54 clojurebot: false

4:54 clgv: ,(letfn [(char-set [c] (->> c (map char) set))] (= (char-set "the quick brown fox jumps over the lazy dog") (char-set (range 97 123))))

4:54 clojurebot: false

4:55 clgv: ,(use 'clojure.set)

4:55 clojurebot: nil

4:55 clgv: ,(letfn [(char-set [c] (->> c (map char) set))] (difference (char-set (range 97 123)) (char-set "the quick brown fox jumps over the lazy dog")))

4:55 clojurebot: #{}

4:56 clgv: ah the \space ^^

5:04 clojure-newcomer: hey guys, is there a library for helping out with versioned REST API's with compojure ?

5:05 dispatching to functions based on the version ?

5:06 augustl: clojure-newcomer: I don't know anything about your API, but it sounds like you might want two completely separate handlers for that

5:06 since paths might be different etc

5:07 and then just wrap each handler in middlewares that dispatches on version

5:07 clojure-newcomer: augustl: ok, have you seen this kind of thing done ? or done it yourself ?

5:07 augustl: well not sure what you mean with dispatching on version

5:07 clojure-newcomer: augustl: so if the accept header specifies 1.0.0 relevant functions would be called for outputting the result xml in the correct format

5:08 augustl: don't think compojure can route on headers, it only routes on method and path afaik

5:08 it's a HTTP library, not a REST library :)

5:08 clojure-newcomer: ah, so in theory the function my route definition calls could take care of dispatching ?

5:09 maybe I could use multimethods :-)

5:09 augustl: clojure-newcomer: probably not to hard to make something like (rest-map (GET "/foo") {"1.0.0" my-handler "1.0.1" my-handler "1.1.0" other-handler})

5:10 clojure-newcomer: that sounds more sensible yeah

5:10 so, (GET "/foo" (version-dispatch {.... }))

5:10 clojure-newcomer: augustl: so the handlers are part of the middleware paradigm ?

5:10 augustl: which returns a handler that chooses which function to call based on whatever

5:10 clojure-newcomer: augustl: yeah right.. your latest looks like the kind of thing I had in mind

5:11 augustl: just a little sure about terminology and handlers...

5:11 got any pointers ?

5:11 augustl: the GET and POST functions (or macros? not sure) end up returning a plain ring handler

5:11 so wrapping and extending is trivial

5:23 clgv: augustl: writing a ring middleware for rewriting paths to version-specific paths could work

5:34 kral: namaste

6:02 muhoo: lein2 won't instal on an embedded platform, because it doesn't have the root certificates and apparently lein2 grabs parts of itself via https

6:03 i'm not a jvm expert by any means. is there any trick to maybe making lein2 NOT use https?

6:04 Fossi: can't you fix the real problem?

6:05 is space really that limited that you want to "disable" ssl?

6:07 muhoo: i have nfi where the jvm gets its certificates from

6:08 if you could point me to some clear documentation on that, i'd be happy to fix the real problem. i haven't found any

6:16 nkkarthik: I have a very small app, I have expose a simple REST api for it... which library should I use?

6:18 vijaykiran: nkkarthik: http://mmcgrana.github.com/2010/08/clojure-rest-api.html

6:19 nkkarthik: vijaykiran: cool... I will look at it... thank you

6:38 muhoo: there's also the wakeful library, and bishop

6:56 meenal: Hi,i see clojure.contrib is not in use, where did clojure.contrib.properties go? it is replaced by which package?

6:58 clgv: ~contrib

6:58 clojurebot: Monolithic clojure.contrib has been split up in favor of smaller, actually-maintained libs. Transition notes here: http://dev.clojure.org/display/design/Where+Did+Clojure.Contrib+Go

6:58 clgv: meenal: seems "clojure.java.data" might be the answer

7:03 meenal: hanks clojurebot and clgv, but clojure.java.data seems to be supporting only beans right now, not properties.

7:03 *thanks

7:04 i am looking at reading properties file, getting data from it as a map, in a clojure way

7:05 clgv: oh ok. java interop should help you there, e.g. ##(keys (System/getProperties))

7:05 ,(keys (System/getProperties))

7:05 clojurebot: #<SecurityException java.lang.SecurityException: denied>

7:05 nkkarthik: muhoo: thank you... I will look at them too

7:06 clgv: Raynes: ping. lazybot is down

7:06 Raynes: clgv: The whole sever is down.

7:07 Or, well, was.

7:07 clgv: Raynes: ah ok. dont know which server it is on anyway ;)

7:07 Raynes: I think it lost network connectivity for a moment.

7:07 The server of milk and honey.

7:07 Anyways, it's coming back up.

7:07 * Raynes goes to sleep.

7:08 clgv: Raynes: you earned it right now ;)

7:09 meenal: clgv: thanks. i was trying to avoid java interop as much as i can

7:09 but i guess for properties, i will have to use it

7:09 clgv: meenal: java interop works pretty well - you should not try to avoid it artificially

7:10 meenal: if you use property access often, you can write one or two clojure functions encapsulating the java interop

7:10 eduard: is it possible to combine -> and 'map'?

7:11 clgv: eduard: with ->> yes

7:11 eduard: what if I need -> first and then to use map on result? is there is juxt-like function?

7:11 meenal: clgv: okay

7:11 clgv: eduard: e.g. that would work (-> 10 range (->> (map inc)))

7:12 &(-> 10 range (->> (map inc)))

7:12 lazybot: ⇒ (1 2 3 4 5 6 7 8 9 10)

7:12 eduard: clgv, thanks

7:36 meenal: clgv:i see (keys (System/getProperties)) helps in getting system information, how do i use to read a properties file and get the values of a key?

7:37 http://stackoverflow.com/questions/7777882/loading-configuration-file-in-clojure-as-data-structure

7:37 how about the above method?

7:43 clgv: meenal: looks good. you do not necessarily need the (into {} prop) since the map-interface is sufficient for a lot of things

7:45 meenal: clgv: thanks :)

7:45 clgv: meenal: take the accepted one from Dave Ray - mayb without that for-expression if you dont need that

7:46 meenal: okay

7:47 i will work it out in my project and see

7:47 thank u

7:53 clgv: i have another question

7:54 i populate a stringbuffer in my code, so that the output of the buffer is <v11:ID id="93"/>

7:54 for inputting the number "93" in double quotes i had to escape the double quotes

7:55 but when i convert it to a string, i get <v11:ID id=\"93\"/>

7:56 i want the buffer output <v11:ID id="93"> after string conversion too

7:56 clgv: meenal: use println to see the actual string output

7:57 the repl will print the escape backslashes

7:57 meenal: i use println for displaying both buffer and string

7:58 buffer print is just wat i want, but after converting it to string, it prints with escape backslash

7:59 clgv: what is your code? what does the input look like? use a paste website

7:59 muhoo: lein2 running (slowly) on a beagleboard: https://www.refheap.com/paste/4091

7:59 meenal: i am sorry, i havent used a paste website. can u give me a url?

7:59 clgv: what meant is ##(let [s "<v11:ID id=\"93\"/>"] (println s) s)

7:59 lazybot: ⇒ <v11:ID id="93"/> "<v11:ID id=\"93\"/>"

8:00 muhoo: meenal: http://refheap.com

8:00 clgv: ~paste

8:00 clojurebot: paste is gist.github.com

8:00 clgv: one of these ^^

8:00 refheap is fine

8:00 muhoo: why clojurebot no love refheap?

8:01 clgv: ~paste

8:01 clojurebot: paste is not gist.github.com

8:01 meenal: k..trying refheap

8:04 firesofmay: Is there any ios testing library in clojure?

8:04 meenal: https://www.refheap.com/paste/4092

8:10 clgv: meenal: prints just fine overhere

8:10 meenal: wierd

8:11 clgv: (println buffer) => #<StringBuffer <v11:ID id="93"/>> AND (println (.toString buffer)) => <v11:ID id="93"/>

8:11 meenal: let me see wats wrong.. thank u

8:13 clgv: meenal: notice the difference here: ##(let [s "<v11:ID id=\"93\"/>"] (println s) s)

8:13 lazybot: ⇒ <v11:ID id="93"/> "<v11:ID id=\"93\"/>"

8:15 meenal: ok.. println just prints fine, while what gets returned is with escape slah

8:16 *Slash

8:16 clgv: meenal: only if you let the repl print the data

8:16 meenal: i thinlk the repl uses pr

8:17 ,(do (println "<v11:ID id=\"93\"/>") (pr "<v11:ID id=\"93\"/>"))

8:17 clojurebot: <v11:ID id="93"/>

8:17 "<v11:ID id=\"93\"/>"

8:18 meenal: oh ok..

8:18 can i change the way it prints?

8:18 clgv: meenal: why would you want that?

8:18 meenal: just want to knw if its possible

8:18 clgv: just use print/println if you really want to output something

8:19 meenal: clgv: sure, thank u

8:26 muhoo: nrepl, clj, and cljs http://bace.s3.amazonaws.com/cljs-and-clj.png

8:27 ro_st: muhoo: oooooh

8:28 i can haz configs, pleez? :-)

9:01 zaargy: when people say clojure is good for concurrency does that mean a specific kind of concurrency? [C[C

9:01 if you just simply want to do lots of things at once but every 'thing' is quite isolated that's relatively easy in any language right?

9:01 * zaargy is confused

9:02 antares_: zaargy: clojure has at least 5 concurrency features, all built with shared (but NOT mutable in the tranditional sense) state

9:02 *in mind

9:02 plus everything java.util.concurrent has to offer

9:02 zaargy: sure, i udnerstand that

9:02 but when you don't need shared state

9:03 ohpauleez: zaargy: If you have isolated processes, sure - but what happens when you need cooperative concurrency? Clojure's is complete in that it offers you all forms of concurrency and a way to get from one form to another. It takes a specific stance on *time* which no other language does

9:03 antares_: when you don't have to share anything, it does make things easier in several languages

9:03 zaargy: sure, i definitely see that

9:04 antares_: then just use a message passing library of some kind

9:04 zaargy: the point is when i use have isolated things going on, i might decide to use a langauge i'm already familar with to do that, so it's trade-off

9:04 i definitely see clojure has distinct advantages as soon as you talk about shared state

9:05 ohpauleez: zaargy: If you have isolated tasks, then you're focused on macro level concurrency anyway, which is much more of an architectural concern than a programming language

9:05 programming language concern

9:06 zaargy: So you'd be spinning up threads or forking things off to other processes

9:06 antares_: zaargy: it depends on what you are familiar with, if the problem inherently requries no shared state, erlang or scala with akka are excellent options

9:06 but clojure or java probably can do well, too

9:07 ohpauleez: Clojure has thread pools configured out of the box and the calling semantics for something like a future are simpler in clojure than in other languages (many due to deref/@)

9:07 zaargy: yeah

9:08 ohpauleez: but just one person's opinion :)

9:08 zaargy: There's also underlying language constructs built on top of Fork/Join, so you get that for free

9:09 in short: Agents, Futures, Promises, Fork/Join, and Atoms all when you need them, all with sane notions of time (where it makes sense), and all with sane use patterns

9:15 ro_st: ohpauleez: :-)

9:15 pubsub is compiling and working

9:15 ohpauleez: YES!

9:15 ro_st: *happiness*

9:15 ohpauleez: ro_st: Enjoy!

9:15 ro_st: question. do i need to create multiple simple busses?

9:15 or can i jam all my topics into a single bus?

9:16 ohpauleez: Jam all of them on one

9:16 ro_st: wicked

9:16 so it's (subscribe topic fn), (publish topic), essentially

9:16 ohpauleez: In the first version of the bus, the bus was a singleton object, but I changed that to make it more functional

9:16 ro_st: with the bus injected so that it's not some ambient value somewhere

9:17 all to the good :-) nice for switching busses to see how the app's behaviour changes, as well

9:17 ohpauleez: ro_st: That's the correct calling semantic, but more often than not, you'll just do:

9:17 (subscribe bus some-fn another-fn)

9:17 and leave it at that

9:17 ro_st: need to publishize as well though, right?

9:18 ohpauleez: when some-fn is called in your code, it will publish its result to the bus automatically. All subscribing funcs will automatically be called

9:18 nope, the bus handles it all

9:18 ohh yes

9:18 ro_st: so why is publishize there, then? :-)

9:18 ohpauleez: you need to publishize the function

9:19 ro_st: yeah

9:19 ohpauleez: (that design decision is to allow you to call the function WITHOUT it going to the bus automatically)

9:19 ro_st: the fun bit for me is that all my model code is in .clj files and cljsbuild's crossovers are copying em over. so my pubsub will be a layer in cljs 'on top' of the model

9:20 this'll be fun to refactor

9:20 right now all my ui is in one mammoth update-ui fn :-)

9:21 clgv: lein-outdated seems broken. it throws a "status 404" exception when connecting to "repo1-maven.org"

9:31 ro_st: ohpauleez: what about atoms and publishize?

9:32 can you opt out of the bus when updating a publishized atom?

9:32 ohpauleez: ro_st: Not currently, but that should probably be changed

9:33 well, hang on, I have to look at the code

9:37 nope, you can't opt-out one-off

9:37 ro_st: not a problem

9:37 was just curious

9:38 going to start with fn based topics first

9:38 ohpauleez: cool, let me know if you hit a snag

9:38 ro_st: oh, i will -grin-

9:38 ohpauleez: :)

9:38 ro_st: ps, it'd rock to have a pubsub impl working in jvm clj

9:39 means can wire and test pubsub defs with midje :-)

9:39 ohpauleez: I've been thinking the same thing

9:39 I'll make a deal with you

9:40 if you tell me a report on what works and what doesn't work with the general protocol and approach

9:40 I'll make a clj bus

9:40 ro_st: oh, happily

9:40 given that you used protocols to begin with, plugging in a clj bus shouldn't be all that tough, right?

9:41 ohpauleez: exactly

9:41 ro_st: https://github.com/Yuppiechef/simple-rabbit/

9:41 ohpauleez: But the feedback is important for the FRP work we're considering for contrib

9:41 ro_st: rabbitmq with clojure

9:42 #justsaying

9:42 FRP?

9:42 ohpauleez: Functional Reactive Programming

9:42 ro_st: oh yes

9:42 once my spike solution with pubsub is working, i'm going to start using phantomjs to write tests for it

9:43 ohpauleez: ro_st: Full FRP thread is here: https://groups.google.com/forum/?fromgroups#!topic/clojure-dev/LzVu4dIvOrg

9:43 ro_st: one small thing i noticed is that the bus isn't always the first arg. in publishize it's second, in subscribe, it's first

9:44 ohpauleez: oh weird, I thought I made it the first for everything

9:44 ro_st: which means -> threading a bus isn't possible

9:44 ohpauleez: ohhh you don't pass the bus to publishize

9:45 oh, yes you do

9:45 ro_st: -grin-

9:45 ohpauleez: hahaha

9:45 I need to look at my own code

9:45 pandeiro: ro_st: check out my casperjs wrapper if you want to write your tests in clojure: https://github.com/pandeiro/ghost

9:46 ro_st: pandeiro: you rock!!

9:46 didn't know about casperjs

9:46 this looks fantastic

9:46 ohpauleez: So I originally did that so you could visually see when you were using the Bus protocols and the Publish protocols, but I'm for changing it if it becomes a headache for you

9:47 ro_st: pandeiro: so this is for functional, integration, acceptance testing? what do you use for unit testing in cljs?

9:48 pandeiro: ro_st: actually i am not using it for testing, but for scraping ajaxy pages like gtranslate

9:48 ro_st: oh right

9:48 pandeiro: but i think there's good potential for all that

9:48 honestly i am new to casperjs too but i was trying to implement a lot of it myself in phantom and luckily someone pointed me to it

9:48 ro_st: ohpauleez: so, are you saying that the arg order matters, or that the bus isn't actually a necessary arg?

9:49 ohpauleez: no it's needed - so one thing can participate with multiple buses and you can track which buses it's publishing to

9:50 ro_st: ohpauleez: i see you ^:export the publishized fn. is this required?

9:50 ohpauleez: ro_st: Nope, just for use at the JS console

9:50 ro_st: ohpauleez: ok, so bus could move to the first arg, then

9:50 doesn't have to, i'm just verifying that it's possible :-)

9:51 ohpauleez: yeah, but it doesn't do you any good for threading - you most likely def the result of the publicized fn

9:51 ro_st: yes

9:51 ohpauleez: you just want it to be consistent

9:52 ro_st: i think the consistency is good, ya

9:52 ohpauleez: for sure

9:54 ro_st: so in my model .clj i'm setting up a (defn some-model-changed []) for pubsub to hook onto, and then from elsewhere in my .clj model i'll call (some-model-changed)

9:58 ah crap. so, there's no way to put a publishized fn into the .clj code for it to call

9:58 without horrible state mutation stuff

9:58 ohpauleez: ro_st: Yeah, you write the function (say - model-updated), then publishize it (def model-updated-pub (publishize model-updated)) then at the top level, wire up the subscribers

9:59 then in your code you just write (model-updated-pub 1 2 3 4)

9:59 ro_st: yup. i have that set up.

9:59 ohpauleez: and the reactions auto happen

9:59 ro_st: except, the call to -pub has to happen from my .clj

10:00 ohpauleez: server side? or just for crossovers

10:00 ro_st: both, although server side probably won't actually want to publish to subscribers. as long as it compiles and doesn't break :-)

10:01 i'm going to move the calls to pubsub stuff off to its own .cljs and stub it out in .clj

10:01 ohpauleez: yeah, from server side, what I do is pull it a level back to the client side and my it call a remote fn

10:02 ro_st: Yeah, that's the only work around right now. I didn't design with crossovers in mind

10:06 foxdonut: https://www.google.com/doodles/hurdles-2012

10:06 12.2s

10:08 stain: I got 16s

10:10 ro_st: ohpauleez: it's working :-)

10:12 like so

10:12 https://www.refheap.com/paste/4094

10:17 ohpauleez: ro_st: Awesome to see. I think as you move forward you'll drop the *-topic name - since publishize is like memoize - it's still a function, you should treat it like one

10:18 mostly for readability

10:18 but this is awesome - I'm excited to hear how it goes for you

10:18 ro_st: its possible. i'm using the earmuffs to make it clear where pubsub is happening

10:19 subscribe quickly became (defn subscribe [topic & fs] (doseq [f fs] (pubsub/subscribe bus topic f)))

10:20 ohpauleez: ro_st: Same for me, you'll see that is being considered for the current protocol (commented out)

10:21 ro_st: can you publishize an empty topic?

10:21 ie, just get a generic topic for the bus?

10:21 (pubsub/publishize bus)

10:21 ohpauleez: you want to see everything coming through the bus?

10:21 ro_st: another good reason to put bus first. if f isn't passed, assume an no-op fn

10:22 ohpauleez: you'd pass identity as the fn

10:22 ro_st: no, just making a topic that doesn't have any args

10:22 gotcha

10:22 ohpauleez: ro_st: You might also want something like subscribe->, which chains subscriptions

10:23 so you can express full workflows

10:23 mdeboard: Is there anything about this macro, particularly lines 79-81 that are written improperly? I get an error message when I run it, but when I replace `~@body' with the actual code I'd otherwise be passing it, it runs fine

10:23 https://github.com/mattdeboard/clj-itext/blob/pdfwriter/src/clj-itext/core.clj#L62

10:23 ro_st: one triggers two, and two triggers three?, therefore, one triggers two and three?

10:24 ohpauleez: one->two, two->three, three->four, etc

10:24 ro_st: gotcha

10:24 i have pretty simple pubsub requirements at the moment; one to one and one to many

10:24 ohpauleez: which is also being considered for the protocol (because I use it a lot)

10:24 ahh cool

10:25 ro_st: but that's how i've planned it. i could very well need a chain

10:25 identity isn't working

10:26 oh, wait, it's not working on the clj side

10:26 isn't there a no-op function already?

10:26 with zero args

10:27 ohpauleez: what would that do in the bus? I can't picture the use-case

10:28 ro_st: https://www.refheap.com/paste/4097

10:29 ln 23 i have (fn [])

10:29 when you want a blank topic that doesn't actually need a fn with args

10:29 ohpauleez: ohhh

10:29 ro_st: this works in cljs but in clj when i use identity in this manner it shouts at me :-)

10:30 ohpauleez: you can just use strings or keywords

10:30 when you want the topic to actually be a topic

10:31 so if you want a broadcast topic (which I think you're going for)

10:31 ro_st: but that'd cause mutlple calls to (topic) to return the same topic due to using the same source literal data

10:31 ohpauleez: just use :broadcast or something to that affect

10:32 mdeboard: are you guys making a game

10:32 ohpauleez: ro_st: this line doesn't make sense (def model-changed-topic (pubsub/topic))

10:32 ro_st: think of topic here like a factory. no args, give me a fresh topic which i'll store at a name to subscribe to. arg, make a topic out of the arg.

10:32 ohpauleez: no

10:33 it's a decorator

10:33 bryanl: is it a normal behavior of the lein midje lazytest to run my tests twice?

10:33 ro_st: right, publishize is. but i'm putting it into a factory, so that i can call it with no args to get a new fresh topic :-)

10:33 ohpauleez: mdeboard: He's battling through a library of mine that hasn't been released yet :)

10:34 ro_st: i'm trying to avoid having to create a no-op function in the model, basically

10:34 mdeboard: I see

10:34 ro_st: because the model will invoke the publishized version of that fn, and never the fn directly (in this case)

10:35 it's not a biggy. i can live with no-op fns

10:36 ohpauleez: ro_st: The return on a publishized-fn is the input to the subscribers

10:37 so a no-op is going to blast nils through the bus

10:37 ro_st: ok, so it has to be something real

10:37 ohpauleez: yeah

10:37 ro_st: cool. i can dig

10:37 ohpauleez: at most: #(identity 5)

10:38 or something to that effect

10:38 metellus: would comment work?

10:38 ,(doc comment)

10:38 clojurebot: "([& body]); Ignores body, yields nil"

10:39 ohpauleez: metellus: nah, still blast nils through the bus

10:39 you want a real return

10:39 metellus: oh ok

10:39 ohpauleez: if you want to signal as a topic, you can use strings, ints, or keywords

10:40 ro_st: ah so i could do (pubsub/topic :model-changed)

10:41 ohpauleez: totally

10:41 I do it all the time

10:41 when you want to broadcast something, that's the way to do it

10:42 ro_st: money for nothing, and your chicks for free?

10:43 bryanl: i'm looking for an idiomatic method for taking the first two items off a list. kind of like first/rest, but i want the first-2

10:43 acheng: ro_st: maybe get a blister on your thumb

10:43 pjstadig: (take 2 ...)

10:43 ohpauleez: bryanl: ^

10:44 acheng: ro_st: (maybe i should say these are quotes from something, lest people think i'm sketchy)

10:44 ro_st: -grin-

10:49 acagle_: /flush

10:53 bryanl: ohpauleez thanks

10:53 ohpauleez: np, thank pjstadig :)

10:54 pjstadig: ohpauleez: from one paul to another...thank you

10:54 ohpauleez: haha

11:08 ro_st: ohpauleez: so, if i use (pubsub/publishize :topic-name bus), that should work?

11:09 mdeboard: publischeisse

11:09 ro_st: i'm getting an exception: throw cljs.core.missing_protocol.call(null, "IPublishable.publishize", t);

11:09 t is "﷐'current-cog-changed"

11:09 mdeboard: sorry for the noise :-)

11:10 mdeboard: lol, just giggling about "publishize"

11:10 ohpauleez: ro_st: You don't have to publishize the kw, you can just do raw publishes with it

11:10 ro_st: ohhh

11:10 fancy

11:11 so then what's the api for publishing? because publishize returns a fn that i can call

11:12 *reads source*

11:13 ohpauleez: ro_st: In short, publishize takes callable or IWatchable things and auto-publishes for you, as a decorator

11:13 otherwise you can broadcast on the bus, like a normal bus, using ints, strings, keywords

11:13 ro_st: ok. just to get on with it, i'm going to use no-op fns

11:13 so that my exposure to the api from .clj is limited

11:14 because i'll definitely have both 'empty' publications and ones with data

11:14 ohpauleez: (publish bus :data-changed {:a 1})

11:14 or (publish bus :data-changed nil)

11:26 ro_st: rocking. works beautifully

11:27 ohpauleez: ro_st: Glad to hear it!

11:28 ro_st: it's rough for now (i re-render entire chunks of the ui), but now the groundwork is laid to update the dom with laser focus

11:28 ohpauleez: awesome

11:28 ro_st: the fun one is going to be inserting elements into the middle of a html node and removing them; basically responding to add/remove events

11:32 pablo_: Hi. I'm trying to find where "to-byte-array" went in Clojure 1.4 (it used to be in clojure.contrib.io). I've been searching for some time but didn't find it...

11:33 ro_st: ~contrib

11:33 clojurebot: Monolithic clojure.contrib has been split up in favor of smaller, actually-maintained libs. Transition notes here: http://dev.clojure.org/display/design/Where+Did+Clojure.Contrib+Go

11:33 pandeiro: clojure.java.io ?

11:34 pablo_: I didn't find it in clojure.java.io

11:36 gfredericks: is there any easy way to use jline programmatically?

11:37 Frozenlock: Is there, by any chance, a forum library for clojure? With compojure or noir?

11:40 pandeiro: pablo_: sorry, dunno.

11:40 pablo_: pandeiro: no problem, thanks

11:41 pandeiro: It looks like it just got ditched. It's a bit annoying, but I can copy-paste the code from contrib...

11:42 scriptor: Frozenlock: like a phpBB or something like that for clojure?

11:45 pepijndevos: is there a vimclojure cheat sheet? I put a lot of effort in getting this thing to run, but I keep forgetting all the useful commands it has.

11:45 Frozenlock: scriptor: yes

11:47 I have a website on Noir and would like to add a forum without using another webserver

11:47 ro_st: i doubt an opensource clojure impl of a forum exists, yet

11:48 too boring a thing to be building with clojure :-)

11:54 si14: hello, guys. what's a decent way to write parser in clojure now?

11:54 arrdem: si14: while the original is out of date, I love fnparse

11:54 si14: looks like there are a bunch of PEG and Parsec-inspired parser generators, but all of them look ead

11:55 *dead

11:55 arrdem: is it alive?

11:55 arrdem: are you kidding me? the original has been dead for two years but there's an updated package

11:56 ohpauleez: si14: Can a parser be dead? once you write a parser, there's nothing really left to do - there's no innovation or features to add, polish, etc

11:56 si14: https://github.com/search?langOverride=&q=fnparse&repo=&start_value=1&type=Repositories looks like the most recent one is 9 month old and without watchers

11:56 Frozenlock: ro_st: yeah I guess... thanks :)

11:56 si14: ohpauleez: fixing bugs, adding combinators/examples/docs, squeezing performance

11:57 arrdem: yeah I agree with ohpauleez here. I though about adding some features to FNParse for a while, and then I realized I could achieve everything I wanted with some tack-on macros that were project specific.

11:58 si14: ok, then what fork is best to use?

11:58 ohpauleez: that's often what I find too arrdem. I either need some lightweight parser or just use antlr from clj

11:58 arrdem: org.clojars.doo/fnparse "2.2.8" is what I used in my last parser project

12:01 ohpauleez: how well does antlr work for you? I looked at it for a while but it didn't have the grammars I wanted packaged so I built em in fnparse

12:01 ohpauleez: arrdem: Pretty well if you just need some AST from a grammar they provide or one you can adapt

12:01 I started with fnparse for a JS-like language

12:02 got pretty far

12:02 si14: arrdem, ohpauleez, anyway, tkanks :)

12:02 *thanks

12:02 ohpauleez: switched to ANTLR and in a week had the same thing, just need some extra work to push it into Clojure data

12:05 si14: np

12:06 arrdem: ohpauleez: ooh.... they have my base language too.... thanks I may have to transition

12:06 casion: does anyone know of a 'functional programming' tutorial written in clojure?

12:06 everything I find is in haskell

12:07 ohpauleez: casion: Neal Ford's Thinking Functionally pieces?

12:07 that are Java, Groovy, and Clojure

12:07 casion: ohpauleez: let me look

12:08 ohpauleez: casion: I think Functional Programming for Java Developers + Neal Ford's Thinking Functional + one of the intro Clojure books should be nice

12:08 maybe 7 languages to round it all out

12:08 casion: I don't know any java at all

12:08 or any oop languages for that matter

12:09 ohpauleez: casion: First language? if not, where are you coming from?

12:09 casion: ohpauleez: been working in c/asm for about 14 years

12:09 and only c/asm, mostly embedded

12:10 pretty closed off from the rest of the world until I decided to change that recently

12:11 ohpauleez: casion: It's going to be a bit of a brain bend, but shouldn't be too bad. I'd suggest just working through one of the intro Clojure books

12:11 casion: i have both the emerick and halloway books

12:11 ohpauleez: Also, the Caves of Clojure is a nice piece

12:12 those are great books

12:12 casion: emericks book is way, way over my head

12:12 trptcolin: ,(doc promise)

12:12 clojurebot: "([]); Alpha - subject to change. Returns a promise object that can be read with deref/@, and set, once only, with deliver. Calls to deref/@ prior to delivery will block, unless the variant of deref with timeout is used. All subsequent derefs will return the same delivered value without blocking. See also - realized?."

12:12 ohpauleez: casion: Try Seven Languages in seven weeks and also read through http://stevelosh.com/blog/2012/07/caves-of-clojure-01/

12:12 casion: it analogizes everything to languages Im not even remotely familiar with

12:12 ohpauleez: maybe those will help

12:13 trptcolin: ,(doc deliver)

12:13 clojurebot: "([promise val]); Alpha - subject to change. Delivers the supplied value to the promise, releasing any pending derefs. A subsequent call to deliver on a promise will throw an exception."

12:13 casion: ok ohpauleez

12:13 trptcolin: ,(let [p (promise)] (deliver p "hi") (deliver p "lolwut?") @p)

12:13 clojurebot: "hi"

12:13 casion: I feel like I understand most of clojure, but how to approach things functionally is not making sense (yet?)

12:13 trptcolin: ^^ just a wrong docstring, or are there situations in which multiple delivers actually throws?

12:14 arrdem: casion: TBH most of the clojure code I write is imperative

12:14 clgv: trptcolin: yes when you deliver to the same promise more than once

12:14 trptcolin: clgv: see the example i pasted above?

12:14 casion: arrdem: any examples?

12:14 arrdem: it's just getting used to using (map) and (reduce) and other applicative functions where appropriate

12:15 clgv: trptcolin: oh. that was changed in 1.3

12:16 ohpauleez: casion: It definitely takes time. Watch Rich's talk: http://blip.tv/clojure/hammock-driven-development-4475586

12:16 the trick is building up to the solution using smaller pieces

12:16 casion: ah, I've watched a few of hickey's talks

12:16 not seen this one

12:17 thank you for the info so far :)

12:17 ohpauleez: totally welcome

12:17 foodoo: casion: Thinking in a functional way is also a matter of practise. Maybe you should check out 4clojure.com

12:17 ohpauleez: casion: ^ also a great suggestion

12:17 trptcolin: clgv: gotcha, thanks. just wasn't sure if it was intentional. we'll open a ticket

12:17 casion: foodoo: ah

12:17 i have the clojure koans as well, been going through those once a day

12:18 I'll add this to my daily routine as well

12:18 I think in large part the concept of immutability just breaks my mind

12:19 at least as a 'rule' rather than an option

12:19 foodoo: casion: sure, if you worked with assembler before then you have a totally different view on the machine

12:19 casion: yeah

12:20 foodoo: so you should consider functional programming as a safeguard. It will restrict you in your ways of solving things, but it will also provide you with the possibility to make some assumptions which are guaranteed to be true

12:21 and you should also understand that there is no 'true' definition of functional programming. About every programming language approaches it differently, if at all. (The same applies to OOP)

12:22 casion: yes, I get that

12:22 if for no other reason than asking questions in #haskell ;)

12:28 otfrom: heading off to skills matter in a bit for this: http://skillsmatter.com/event/home/london-clojurians-user-group

12:28 still spaces if anyone is in London and fancies coming

12:29 casion: these caves of clojure posts are fantastic

12:30 * m0smith agrees with casion

12:35 ohpauleez: casion: Glad to hear!

12:45 acheng: maybe a wiki somewhere should list the current-best clojure caves for things like functional programming, concurrency, etc

12:46 antares_: Clojure folks, don't forget to cast your vote in this "JVM priorities" survey: http://www.infoq.com/research/priorities-java-jvm

13:31 gerunddev: Ah core.logic... just when I think I've got you I find something else I don't understand!

13:31 https://gist.github.com/3287562

13:31 I really thought the first constraint would mean no results whether or not view and search are present.

13:32 But in unit tests if I pass in nil for design but a value for view I get ["_design" nil "_view" "view"]

13:35 amalloy: != is a tricky animal, gerunddev. i don't really get it either, and my general approach is to stay away from it

13:35 gerunddev: amalloy: Have you found another trick to avoid nulls?

13:36 amalloy: don't pass nils to begin with. core.logic doesn't create nils for you in most of its core primitives. for example, emptyo rather than scheme's nullo

13:36 gerunddev: BTW I updated my gist to have code, unit test and results: https://gist.github.com/3287562

13:37 Ok so I could check for nulls before passing into my logic code I guess

13:37 *nils

13:37 amalloy: ie, i haven't avoided nils because i haven't encountered one yet

13:39 gerunddev: I am destructuring keys and trying to interpret the next step based on a bunch of rules.

13:39 If a key wasn't passed in the symbol will be nil...

13:39 I'd like to say oh you passed :a and :b, but not :c and so I'll go down this path...

13:43 amalloy: Ok I figured out a solution. Introduce a new lvar, put the constraints on that... Solution added to the gist: https://gist.github.com/3287562

13:44 amalloy: that doesn't make sense to me. i suggest asking dnolen` what's up

13:45 gerunddev: dnolen`: Does this make sense to you? https://gist.github.com/3287562

13:45 milinda: anyone know way to store zip archive as a blob via sqlkorma?

13:45 gerunddev: dnolen`: Looks like I had to add an extra lvar to constrain against nil...

13:52 amalloy: fwiw, gerunddev, i doubt nil is relevant; have you tried the same thing replacing nil with, say, 5? it's probably != that's acting oddly, not nil

13:59 eggsby: Hmm, I'm giving a short 5 minute talk on clojure at work to try to get other teams to start using it... what sort of stuff should I try to fit in there... hello world doesn't seem like a good example of it's power, but I'm afraid stuff like macros/lazy-seqs would probably be too advanced...

13:59 technomancy: wow, the original jdk6 EOL date was last month

14:00 duck11231: is there an up to date ants demo? That was pretty cool originally

14:00 naeg: eggsby: I have a link for you and I think Clojure Programming has a section on that - checking both...

14:00 amalloy: eggsby: demoing some math stuff is pretty easy and somewhat awe-inspiring

14:00 technomancy: it got pushed back to november though

14:00 maybe we can have a deprecation party at the conj =)

14:00 amalloy: eg, finding the sum of the squares of the first hundred odd fibonacci numbers

14:00 scriptor: eggsby: what kind of stuff do you work on at work?

14:01 gerunddev: amalloy: Ok now the original code is working fine... maybe I'm just letting nrepl get in weird states over time...

14:01 hiredman: technomancy: last I heard clojure's minimum jre is still 1.5

14:01 amalloy: gerunddev: no, i was able to repro your original problem with copy/paste into a fresh repl

14:01 naeg: eggsby: yeah, Clojure Programming has: Chapter 19. Introducing Clojure into Your Workplace which might help you and also this link: http://www.andrewhjon.es/142343729

14:01 amalloy: last time i did that, eggsby, i got the clojure program right on the first try, and made two or three subtle errors in my C version

14:02 eggsby: thanks guys!

14:02 otfrom: @ryangreenhall is giving a great shout out to the friendliness and thoughtfulness of this channel. Thanks everyone for being a great and welcoming place.

14:02 (I'm at the London Clojurians skills matter talk btw)

14:02 casion: amalloy: thanks again for writing that code last night, I'm slowly figuring out the concept of it

14:02 gerunddev: eggsby: Another suggestion, maybe use light table? I used it to show a coworker.

14:02 eggsby: scriptor: I work at an affiliate advertising company, so it's mostly tracking events and asking questions about those events

14:03 amalloy: casion: uvtc apparently plans to write a blog post about it

14:03 make sure you look at the updated version; i was managing cooldown a bit wrong

14:03 casion: amalloy: about the 'problem' i presented?

14:03 amalloy: and my solution to it, yes

14:03 casion: amalloy: yes, I was going to ask about that

14:03 gerunddev: amalloy: Oh no, that's scarry that my tests are passing now. Well meeting time, then I guess I'll get back to it. Thanks for the help!

14:04 naeg: otfrom: I can only confirm that, after being around for a few days

14:05 not all channels are like that...

14:05 otfrom: naeg: agreed. Just thought I'd pass on the love from the talk.

14:06 dnolen: gerunddev: sorry didn't see your earlier question until now.

14:07 gerunddev: dnolen: I hope the gist is clear, it seems that != isn't acting the way I expected

14:08 naeg: otfrom: sounds like an interesting talk...is it? probably useful for eggsby too

14:08 dnolen: gerunddev: it's the first test that's giving you the weird result right?

14:09 gerunddev: dnolen: Yes

14:09 dnolen: gerunddev: oh right.

14:09 gerunddev: core.logic expressions are not regular clojure statements

14:09 amalloy: oh, he needs an (all ...)

14:09 dnolen: gerunddev: uri-path is not correct, you need a fresh around that or all.

14:09 gerunddev: So adding the fresh in the solution was the fix?

14:10 amalloy: now i feel silly for not noticing that myself

14:10 dnolen: gerunddev: all just macroexpands to (fresh [] ... goals ...)

14:10 gerunddev: so no ... that extra var is not necessary.

14:10 gerunddev: it's the conjunctive aspect of fresh that fixed your problem.

14:11 gerunddev: Yeah, that's funny. I didn't need x, but fresh was the real fix. Ok, so when do I need an all or fresh?

14:11 dnolen: gerunddev: all is idiomatic since you don't need to declare any vars.

14:12 amalloy: gerunddev: anytime you want to make multiple logic statements you need to wrap them up in *some* core.logic container

14:12 dnolen: yep

14:12 amalloy: usually they're already inside a fresh or whatever, so that you don't have to do anything. but at the top level of a regular defn...

14:12 gerunddev: Ok so start everything with a fresh or all (if no vars are needed). Got it!

14:12 dnolen: gerunddev: I made that mistake recently too, it's easy to forget.

14:14 gerunddev: perhaps an argument for defg sugar that does that for you ...

14:14 gerunddev: Great thanks for the help! I'm loving core.logic for problems, just need to keep understanding it better

14:14 amalloy: defg, for goal? does that exist already, or are you proposing it?

14:15 dnolen: amalloy: doesn't exist ... perhaps worth considering if the sugar should be comprehensive.

14:16 amalloy: I made a similar mistake w/ let.

14:16 amalloy: i've done it too

14:17 but i'm not sure defg is a good solution. it will train me to look at (defg f [x y] (== x 1) (== y 2)) and say "oh, that's fine". then the pattern-recognizer in my brain will not notice the difference in (defn f [x y] (== x 1) (== y 2))

14:18 dnolen: amalloy: yeah, I somewhat agree. it's an surprise that's probably best for people to actually understand.

14:18 amalloy: it's just annoying because it won't fail, you'll just get strange results.

14:19 won't "always" fail I mean.

14:19 amalloy: right

14:21 what would be ideal is if you could somehow hook into the macroexpander/compiler, and complain if the form "above" a logic statement is (do ...)

14:22 but i don't think there's any way to do that currently

14:22 (nor am i proposing there should be, really)

14:28 acagle_: /flush

14:32 acheng: it seems if something takes 3 screens to print out at the repl in emacs, the repl gets very slow. ... and stays slow even for later expressions like (inc 3)

14:32 casion: acheng: I've noticed this as well

14:33 technomancy: wrapping extremely long lines is pretty slow in emacs, especially with screen splits

14:33 C-c M-o clears output in slime IIRC

14:33 acheng: casion: i'm on windows. i was wondering if it was just my machine. i can even hear something like a cpu fan spin up

14:33 casion: I'm in os x, and it happens to me

14:33 technomancy: usually takes more than 3 screens to cause a slowdown though

14:33 acheng: ooh, thanks technomancy!

14:34 that improves things

14:35 duck11231: never try to print a whole bunch of xml at the clojure repl. It causes no end of trouble

14:35 technomancy: it's usually fine if you have newlines

14:37 acheng: if i have a zipper from an xml string and it has :tag :attr and :content... how do i get the content for something with :tag foo ? (xml-> foo :content) ?

14:37 amalloy: but technomancy, isn't that wasting like three bytes for every xml tag? i really want to use xml for my super-compact format

14:38 acheng: duck11231: the reason i'm printing xml to the repl is that i'm trying to figure out zippers

14:38 hiredman: technomancy: if you use prn the newlines will all get escaped, so you are boned

14:39 duck11231: acheng: right, I was just noting that every time I've tried to print out xml to slime I've ended up regretting it

14:39 technomancy: hiredman: yeah, that sucks =\

14:40 duck11231: That's why I tend to prefer using the logging lib and running my server from a terminal, that way if I want to dump anything, I can just hit F12 to pull down my terminal

14:44 piranha: still no replies to my question about protocols in clojure mailing list... :( I wonder if I should escalate that somehow - it looks like a bug to me.

14:45 acheng: nakkaya.com/2009/12/07/zipping-xml-with-clojure/ has an example... the paintings zipper has something with tag :img that has :content nil... how would i verify that it is nil using clojure code? ... or let's imagine that it has content "foo"... how would i verify that?

14:45 llasram: piranha: What was the subject line for your post?

14:45 piranha: llasram: ClojureScript & protocols

14:48 llasram: Oh, Clojure*Script*. Sorry, I haven't used yet

14:48 piranha: np :)

14:48 _fogus_: Has anyone experimented with SCXML and Clojure?

14:49 piranha: I'm just wondering if 2-day lag is ok for this mailing list or does this mean that message probably won't be replied ever...

14:50 technomancy: the mailing list really isn't what it used to be =\

14:50 clojurebot: list* doesn't actually make a `list?`

14:51 llasram: Thanks, clojurebot!

14:51 pepijndevos: where is lazybot?

14:51 llasram: piranha: Yeah, hard to say. Usually people jump on pretty quickly if they can help.

14:51 duck11231: piranha: just like any ML, sometimes good posts slip through without any response

14:52 piranha: yeah, I see... I'll wait until tomorrow's morning and probably will reply to myself. I guess I can't just create a ticket in an issue tracker, haha :-)

14:52 llasram: Maybe someone here has some ideas? FWIW, nothing leaps out of me about your code, but like I said, don't know what quirks ClojureScript has

14:53 _fogus_: technomancy: The ML seems the same as always... except for a different Ken

14:53 duck11231: if you can find a way to make a reproducible test case, you'll discover your error and have no need for the test case (at least that's how it usually works)

14:54 llasram: piranha: Well, there is one thing I can think of: re/evaluation order. If the protocol is loaded, the record defined, then the protocol re-loaded, the record can end up implementing the earlier version of the protocol, which is no longer what the protocol vars reference. (Or at least that's what can happen in JVM Clojure -- no idea if it also plagues ClojureScript)

14:54 acheng: (ah, i think "text" is the answer to my question... the return value of (xml-> paintings :tag-name text) seems to match any edits i make)

14:55 piranha: llasram: hm, is order of importing is somehow wrong in my code?

14:55 m0smith: piranha: where is your code? I just worked through getting protcols to work in clojurescript

14:56 piranha: m0smith: oh, 1 second

14:56 m0smith: https://github.com/piranha/cj-locations/blob/master/src/google.cljs

14:56 here is a file which imports protocol and implements it

14:56 protocol is, naturally, in file 'map.cljs'

14:56 llasram: piranha: Oh, no. I'm talking about something that can happen in the REPL. If this happens with a fresh environment, loading things in normal order, then the issue I mentioned is not the problem

14:56 piranha: ah, I see...

14:57 llasram: well, here it looks like defrecord has no idea how to generated method names based on protocol or something like that

14:57 I don't know really :)

14:57 m0smith: so does this look wrong? :-)

14:58 m0smith: piranha: I did two things differently in https://github.com/m0smith/crossfire/blob/master/src/crossfire/miss.clj

14:59 piranha: hmhmmh

14:59 I tried with extend-type

14:59 m0smith: First, I used extend-type

14:59 piranha: but I'll try once again :)

15:00 m0smith: Second I used :require :as on the protocol and referenced it that way

15:00 piranha: m0smith: I see... I'll try, give me few minutes :)

15:00 m0smith: lines 9 and 16

15:00 k

15:01 piranha: btw, when I did :require [locations.map :as lmap] in my core.cljs, I couldn't refer to them as lmap

15:01 pandeiro: i created an indexed seq with entries like [0 "foo"] [1 "bar"] ... and say i want to return a sub-sequence of just items 300 through 350

15:01 i thought i could use (select-keys indexed-seq (vec (range 300 350)))

15:01 but i that would work if it were a vector i suppose

15:02 m0smith: pandeiro: (take 50 (drop 300 ( your-seq)) ?

15:02 piranha: m0smith: :require :as helps!

15:02 oh yeah

15:03 %)

15:03 technomancy: pandeiro: interestingly select-keys accepts a vector, but it returns a map

15:03 piranha: I should reply to my email just in case

15:04 amalloy: it couldn't really work well otherwise, right, technomancy?

15:04 m0smith: piranha: glad it helps. I had some help on this channel the othernight getting it right.

15:05 piranha: :)

15:06 pandeiro: technomancy: yeah i noticed that, b/c it uses (find...) under the covers, which works on vectors

15:06 m0smith: that works too

15:06 technomancy: amalloy: right, not reliably across a non-contiguous key range

15:06 amalloy: technomancy: even a contiguous key-range

15:07 (-> (select-keys x [k]) (get k)) should return the same as (get x k), for all k, i think

15:09 technomancy: hrm; arguable

15:09 well... yeah, probably

15:10 piranha: m0smith: do you by any chance know then why is this https://github.com/piranha/cj-locations/blob/master/src/core.cljs#L18 compiled as lmap.Map instead of locations.map.Map? :)

15:11 or maybe someone else knows... it works normally in some places it seems though

15:12 m0smith: piranha: It is in both the :use and the :require and the one in :require is missing the [ ] around it. You can 2 things being required but only one vector

15:12 piranha: oops

15:12 i'm dumb apparently

15:12 m0smith: thanks :)

15:12 m0smith: when I first started I was missing the : on :use and it mostly worked

15:13 piranha: :-)

15:13 another question: does anybody here use some analogue of promises/futures?

15:13 to abstract at least somehow from js endless callbacks

15:13 m0smith: piranha: I have been banging my head on that same question.

15:13 piranha: :-)

15:14 m0smith: I found an article by Brian McKenna, plus this piece of code: https://github.com/netguy204/MOVE/blob/master/src/move/macros.clj#L29

15:14 m0smith: javascript is not threaded, except for WebWorkers and AJAX as far as I can tell

15:14 piranha: ajax is not threaded at all

15:14 it's just asynchronous

15:15 web workers are threads but I don't know anyone who uses them

15:15 m0smith: piranha: I saw that article as well

15:15 piranha: it's a bit like some monad, this doasync

15:16 I would love to have some abstraction but I still am not used to clojure that much to see what can be done

15:16 and what's the best way :\

15:16 I would love to have someone more experienced do that part for me :D

15:16 m0smith: piranha: I was going to look into WebWorkers to see if it can be done

15:16 piranha: m0smith: well, I guess it can, but it won't help you much I think

15:16 m0smith: I am still thinking about it but you can watch the crossfire project

15:17 piranha: everything is callbacks

15:17 ibdknox: there's a long discussion about this on the dev list

15:17 piranha: ibdknox: oh, interesting. Is there any outcome?

15:17 ibdknox: people are working on it :)

15:17 piranha: m0smith: crossfire is a game, right?

15:18 ibdknox: hehe :) is there any work in progress or something just to poke something at least? :)

15:18 m0smith: piranha: yes, a Battelship-ish game. I am using it mostly as a way to investigate some ideas related to other projects

15:18 piranha: ibdknox: can you maybe tell me a name of thread with discussions? I couldn't find anything...

15:18 ibdknox: piranha: https://groups.google.com/d/topic/clojure-dev/LzVu4dIvOrg/discussion

15:18 piranha: thanks

15:18 acheng: does lein search work for you right now? i get a 404... is a repository down?

15:19 piranha: btw, is there any site which can show you clojure libraries available on clojars?

15:19 and if not, why? :))

15:20 antares_: piranha: there is a couple, and a new one in the works, that list prominent libraries

15:20 uvtc: piranha: I'm glad you asked...

15:20 antares_: there is interest in getting a better browsing UI into clojars.org eventually

15:20 uvtc: piranha: The Dining Car is new, and lists a few: http://www.unexpected-vortices.com/clojure/dining-car.html

15:20 antares_: piranha: some projects have their own sites, e.g. http://clojurewerkz.org

15:21 piranha: yep, I've seen clojurewerkz

15:21 uvtc: casion: ping

15:21 casion: sup

15:21 piranha: uvtc: dining car looks like something curated by hand, right?

15:21 casion: I heard you were writing a blog post about the code amalloy did?

15:21 xeqi: acheng: the index on central changed, and lein needs to update... theres an issue for it

15:21 piranha: antares_: is clojars.org open source?

15:21 xeqi: piranha: https://github.com/ato/clojars-web

15:21 uvtc: You were asking about amalloy's example last night. I wrote up a blog post explaining the code. Have a look: http://www.unexpected-vortices.com/blog/2012/clojure-battlebots.html

15:22 acheng: xeqi: thanks!

15:22 casion: uvtc: awesome

15:22 uvtc: :D

15:22 casion: is that the updated code?

15:22 antares_: piranha: https://github.com/ato/clojars-web/

15:23 uvtc: piranha: Yes, hand-curated --- hopefully by the community though. I don't know many libraries.

15:23 piranha: I guess I have to update my laptop if I want to continue my endeavor with clojure...

15:24 uvtc: well, this solves part of the problem - list of quality/mature libraries.

15:24 uvtc: casion: Yes, it's amalloy's latest.

15:25 casion: uvtc: reading it now

15:34 uvtc: so at the conceptual level, it's just finding the 'next attacker', subtracting that distance from the cooldown of both fighters, dealing damage, thn returning a list of the 2 fighters new state

15:34 is that correct?

15:35 scriptor: casion: I've only looked at it briefly, but that's what fight-one-round seems to do

15:35 uvtc: Well, you only subtract it from the other fighter's cooldown-remaining. The one who did the attacking gets its cooldown-remaining reset to max.

15:36 casion: uvtc: ahhhh that makes more sense

15:36 scriptor: find the next cooldown, do damage, move clock forward by that cooldown (ie. set cooldowns to new points)

15:37 casion: alright, this explanation was incredibly useful

15:37 uvtc: Yay! {big smile}

15:38 casion: the idea of returning a list of an updated state completely eluded me

15:38 and the lazy evaluation I didnt catch either, I was stuck on why the code didnt just blow up haha

15:39 uvtc: You can use recursion, and pass state along as args into the recursive function, but amalloy's method here skipped that and just used iterate + the `fight-one-round` function.

15:39 casion: well, my next task then, is to write this differently on my own

15:40 uvtc: (That is, he let `iterate` do that recursion for you.)

15:40 casion: it seems like you could do this without tick

15:41 and simply subtract the min from both fighter's cooldowns

15:41 that sets the min result to 0, and decrements the other to the new state

15:42 pandeiro: how can i match a paren in java regex?

15:42 ibdknox: \(

15:43 pandeiro: huh

15:43 how can i return what's inside parens?

15:43 jodaro: is that the answer or a new emoticon?

15:44 unhappy cylon

15:44 TimMc: pandeiro: \(([^)]*)\) ?

15:45 pandeiro: Unless you want nested parens, in which case you'll need to add a stack and a loop (making it a context-free parser).

15:45 m0smith: I love the quote from the Joy of Clojure: If you think you have a problem you can solve with regular expressions, now you have two problems

15:45 TimMc: m0smith: It's an old quote.

15:45 jwz, maybe?

15:45 pandeiro: yeah that's a classic

15:45 TimMc: ibdknox: thanks

15:45 amalloy: yeah, jwz is usually credited with it. dunno if he was first

15:46 m0smith: TimMC: All old things are new again. We are talking about LISP and all of a sudden 50 years of computer thought become more relavant

15:46 TimMc: It's probably an appropriation of an older adage.

15:46 pandeiro: TimMc: not sure why the second closing paren goes inside the square brackets

15:46 wait, is that a typo? there are three closing parens

15:46 TimMc: pandeiro: It doesn't; [^)] means "anything but a closing paren".

15:47 [^\)] if that offends your sensibilities.

15:47 pandeiro: ah got it

15:47 makes it clearer with the escape i think

15:48 TimMc: One of the rare cases in regexes. :-)

15:48 amalloy: :( to adding \ arbitrarily because you aren't comfortable with how [] works

15:48 it's like putting ) on its own line - makes you comfortable for a while, but ultimately hinders understanding

15:50 pandeiro: amalloy: good point, i am definitely not comfortable with how [] works

15:50 langmartin: so I have a program that's been running in production for a few months and a some of my recent patches make it fire the garbage collector every few seconds on Linux (not on mac)

15:50 TimMc: amalloy: What it really means is that one's editor is insufficient. :-P

15:50 langmartin: If there isn't an easy answer to this it's probably one I'll have to trace for

15:51 providing the jvm command line option to stop explicit gc "fixes" the issue

15:51 the interesting part is that it's a boring set of patches, with no new dependencies

15:51 TimMc: $ grep 'System/gc' . --include='*.clj'

15:51 langmartin: I did use System/getenv for the virst time

15:52 amalloy: $ find -name '*.clj' | xargs grep System/gc ## more flexible

15:52 langmartin: TimMc: tried that, no match

15:53 TimMc: Oh, and throw an -nR in there, or use amalloy's suggestion. -.-

15:53 amalloy: langmartin: does the behavior go back if you revert the patches? could be unrelated

15:53 TimMc: langmartin: Is it just producing more garbage?

15:54 langmartin: the behavior does go back if I revert the patches

15:55 TimMc: that's a good question, of course. the command line switch -XX:+DisableExplicitGC is what makes the vm stop spiking cpy

15:55 cpu, that is

15:55 which shouldn't stop anything but explicit collection

15:56 I was hoping there was some known thing in clojure (1.3) about the return value of System/getenv or something easy

15:56 hiredman: langmartin: how are you running the app?

15:56 langmartin: hiredman: from an lein uberjar

15:57 hiredman: huh

15:57 langmartin: java -XX:+DisableExplicitGC -cp platform-standalone.jar platform.core -v -d

15:58 if there isn't a known issue I can trace it down, I'll just have to do it after a few unrelated things done

15:58 hiredman: langmartin: so by "it's a boring set of patches" you mean there are no direct calls to System/gc in the patches? have you looked for indirect calls?

15:58 langmartin: hiredman: correct. It's mostly moving names around in maps

15:58 there are no explicit calls to System/gc in my code at all

15:58 TimMc: At this point I'd try attaching a debugger and breakpointing System/gc.

15:59 Are there other ways of invoking GC?

16:00 hiredman: langmartin: yeah, but if your code calls X and X calls System/gc

16:00 langmartin: sure

16:00 I went looking at gc as a culprit because it was spiking the cpu while my code was idle

16:00 waiting for incoming network connections

16:01 m0smith: langmartin: I have seen this behavior in Java programs from both XML parsing and CORBA message passing. It has also occured with Spring when the context gets initialed a bunch of times

16:01 langmartin: wherever System/gc is getting called, I don't think it's in anything that's started by a call in my program

16:02 m0smith: I'm not intentionally doing any of that, there must be an xml parser in log4j somewhere, though

16:33 casion: if I have a vector of maps, how do I get the a new vector of maps where :key is x

16:34 and all associated keys in those maps intact

16:34 amalloy: first, clarify what "where :key is x" means

16:35 casion: say I want to find all maps in a vector with :key 10

16:36 amalloy: try ##(doc filter)

16:36 lazybot: ⇒ "([pred coll]); Returns a lazy sequence of the items in coll for which (pred item) returns true. pred must be free of side-effects."

16:36 nDuff: casion: Do you really need a vector, or just a sequence?

16:36 technomancy: or filterv if you like

16:38 Raynes: He is such a square []/

16:38 amalloy: nobody(1) ever really needs a vector

16:38 (1) except people who already know this and don't ask the question

16:38 casion: nDuff: I have no idea

16:39 technomancy: I wonder how often mapv/filterv are abused simply to avoid doall

16:39 S11001001: I don't need a vector

16:39 technomancy: also: is that an abuse?

16:39 I think so

16:40 S11001001: technomancy: depends if you need a vector; it'd still cons less to keep the doall result

16:40 technomancy: I'd argue that using mapv communicates to the reader that a vector is specifically needed

16:40 S11001001: better than vec?

16:41 technomancy: so if you use it to replace doall it could cause confusion about the intent of the code

16:41 amalloy: S11001001: you think so? conj! probably doesn't allocate that much, does it?

16:41 S11001001: amalloy: oh, right, I forgot that you could implement mapv without plain map and into

16:43 pandeiro: i have '(2007 :a :b :a :b :a :b 2008 :a :b :a :b) and i want '((2007 (:a :b :a :b :a :b)) (2008 (:a :b :a :b))) - which hofs will do best here?

16:44 amalloy: partition-by?

16:45 casion: amalloy: so does something like (filter #(zero? (:key %)) coll) seem reasonable?

16:45 amalloy: sure

16:46 casion: ok thank you

16:46 amalloy: personally i prefer (filter (comp zero? :key) coll)

16:47 pandeiro: amalloy: sure got that, and then once i have ((2007) (:a :b :a :b)), partition 2 ... etc? is there no easier way?

16:48 casion: amalloy: ah ok, I wasn't familiar with comp

16:59 muhoo: hehehe, nrepl and pprint are not happy. it can get into an endless loop printing unlmited recursion levels

16:59 and yes, i have (alter-var-root *print-level* (constantly 15))

16:59 pprint seems to ignore that when using nrepl

17:11 dakrone: ,(doc *print-level*)

17:11 clojurebot: "; *print-level* controls how many levels deep the printer will print nested objects. If it is bound to logical false, there is no limit. Otherwise, it must be bound to an integer indicating the maximum level to print. Each argument to print is at level 0; if an argument is a collection, its items are at level 1; and so on. If an object is a collection and is at a level greater than or equal to th...

17:11 dakrone: muhoo: you are setting *print-level* to a function instead of a value

17:12 ,(binding [*print-level* 2] (println {:a {:b {:c {:d 1}}}}))

17:12 clojurebot: {:a {:b #}}

17:12 amalloy: dakrone: no he isn't

17:12 but in using alter-var-root instead of binding, he's probably not impacting the thread-local binding that his repl already has

17:12 dakrone: amalloy: you are correct, I was thinking binding, not alter-var-root

17:14 if you're interested in setting it globally, why not just use (set! *print-level* 15)

17:20 technomancy: man... tempted to use deliver as a 1-arg funcall here

17:20 (-> (cemerick.drawbridge/ring-handler) (basic/wrap-basic-authentication authenticated?) (deliver req))

17:20 amalloy: technomancy: just define your own funcall in a utils lib somewhere

17:21 or use useful.utils/invoke

17:21 technomancy: this is a lein-template, so that's not really appropriate

17:21 amalloy: neither is using deliver as a stand-in for funcall, man

17:22 technomancy: I know; just sharing my internal struggles and temptations.

17:23 http://p.hagelb.org/sample-web.clj.html <- not a big fan of the way conditionals fit into the -> wrapping pattern

17:24 (if (= "/repl" (:uri req)) ...) and (if (env/env :dev) ...)

17:26 muhoo: dakrone: IllegalStateException Can't change/establish root binding of: *print-level* with set clojure.lang.Var.set (Var.java:233)

17:27 technomancy: awesome, drawbridge wrapped in friend for auth!

17:27 hiredman: technomancy: you know, you could use define some routes

17:27 just

17:27 technomancy: muhoo: friend is overkill here

17:27 hiredman: oh yeah, that would be a lot nicer for the repl bit

17:27 dakrone: muhoo: interesting, it works at the repl, perhaps a clojure version difference?

17:27 technomancy: hiredman: still sucks for wrap-stacktrace though

17:28 muhoo: dakrone: i'm on 1.4, using nrepl

17:29 dakrone: muhoo: same: http://p.draines.com/1344374866770fec31fe4.txt

17:29 raek: muhoo: the ordinary clojure repl is executed inside a clojure.main/with-bindings

17:29 hiredman: technomancy: higher order wrapping

17:30 (-> (wrap-cond trace/wrap-stacktrace env :dev) ...)

17:30 technomancy: hiredman: starting to look conduity =)

17:34 muhoo: raek: is there any way to get underneath that and change those bindings?

17:34 llasram: Huh. Why does the docstring for `deliver` say "A subsequent call to deliver on a promise will throw an exception," when that is not in fact true?

17:35 Subsequent attempts actually just return `nil`, which IMHO seems more sane anyway

17:35 muhoo: llasram: jira

17:36 raek: muhoo: if you are in the dynamic scope of a 'with-bindings' or 'binding', then you can just use 'set!'

17:36 amalloy: llasram: the impl changed in 1.3; the docstring, predictably, did not

17:36 llasram: amalloy: Ah, that makes sense

17:36 hiredman: :(

17:36 muhoo: raek: theoretically, however, set! throws an exception in the repl, strrangely.

17:36 hiredman: that is horrible

17:36 llasram: muhoo: Man, time to go home. I thought "good idea," and opened my work Jira instance

17:36 hiredman: it should throw

17:37 muhoo: llasram: hahaha

17:37 amalloy: hiredman: i like the nil behavior

17:37 muhoo: llasram: beer-thirty

17:39 raek: muhoo: in which repl?

17:39 muhoo: raek: nrepl

17:39 raek: sounds like nrepl is missing something, then...

17:49 akhudek: It is possible to use the SVN version of the closure library with clojurescript?

17:49 trptcolin: deliver docstring patch is now in jira, fwiw - http://dev.clojure.org/jira/browse/CLJ-1038

18:04 m0smith: ibdknox: is crate ready for people to try?

18:07 * nDuff ponders soliciting quotes for an implementation of Sarah Gelper's Robust Holt-Winters for Incanter

18:09 naeg: btw, this is the talk otfrom was talking about: http://skillsmatter.com/podcast/home/reviving-uswitchs-back-office-with-clojure

18:46 holo: good day everyone

18:49 mdeboard: hi

19:02 holo: in noir, how do i switch between development and production mode?

19:08 xeqi: holo: `lein run :prod` I think

19:08 holo: oh, i see, that is what is passed to -main. makes sense, thanks xeqi, again

19:10 amalloy: lein with-profile :prod run?

19:16 holo: amalloy, thanks

19:36 mabes_: in slime debug can you see the locals values at the time of an exception if you use the local clearing option in clojure 1.4?

19:40 Frozenlock: I'm ready to try clojurescript! :D Any recommendations on stuff to read on how to get started?

19:41 xeqi: beyond lein-cljsbuild ?

19:41 LuminousMonkey: I'm just trying ClojureScript myself, so I would be interested.

19:42 Frozenlock: xeqi: I was reading it at this very moment! Guess I'm on the right path :P

19:42 LuminousMonkey: lein-cljsbuild is great, but the only example I can find is Twitterbuzz.

19:42 Frozenlock: But yes, if you have other suggestions I would take them.

19:44 xeqi: have you seen http://www.chris-granger.com/2012/02/20/overtone-and-clojurescript/ ?

19:44 LuminousMonkey: Oh, nice.

19:45 Frozenlock: ibdknox is everywhere :P

19:47 xeqi: as far as libraries go, ibdknow has some and ohpauleez made some at https://github.com/shoreleave

19:48 *ibdknox

19:50 LuminousMonkey: Thanks xeqi

19:51 Frozenlock: Thanks indeed

19:54 m0smith: xeqi: I can't find any examples of how to use shoreleave

20:07 Frozenlock: I'm just blown away by the overtone-and-clojurescript example. It looks so.... simple.

20:07 technomancy: are there any existing nice HTML error pages for compojure?

20:07 (not stacktrace middleware; thinking of something prod-appropriate)

20:08 Frozenlock: Isn't the stacktrace only in dev mode?

20:08 gfredericks: "We feel pawful."

20:08 technomancy: Frozenlock: it's wherever you decide to apply the middleware =)

20:09 * Frozenlock hides in a dark corner

20:09 technomancy: compojure doesn't have a notion of "dev mode"

20:11 xeqi: technomancy: wouldn't you want those to look like the rest of the site?

20:11 weavejester: technomancy: I haven't seen any prod error pages, but there must be some nice ones out there that are just HTML

20:12 technomancy: xeqi: yeah, but I'm creating a lein-template project, so a generic starter would be fine

20:12 I guess there's no reason to look for something compojure-specific

20:15 weavejester: With there's a compojure template for Lein I've been working on.

20:16 At the moment it just sets up a basic route and some tests

20:23 technomancy: I'm working on a heroku one that adds in environ and drawbridge

20:23 gfredericks: how about a white page with a rectangle in the middle around some red text that reads "We're sorry, but something went wrong."

20:23 and maybe a questionable claim about having been notified about the issue

20:24 hiredman: and a uuencoding of the stacktrace

20:25 * gfredericks just learned something

20:26 hiredman: may we all be so lucky

21:15 amalloy: hiredman: why uuencode rather than base64?

21:27 gfredericks: amalloy: then I wouldn't have learned anything

21:31 hiredman: amalloy: no reason

Logging service provided by n01se.net