#clojure logs

2013-08-23

00:47gdev`cbp, couldn't reproduce it, closing the trouble ticket =/
00:51babu`dakrone, Any idea when you will be able to implement proxy auth for clj-http.client? I looked around and found http.async.client and converted my code to use that. But ^C^K with clj-http is instantaneous but with the async it takes several seconds.
00:52dakronebabu`: I will not be able to get to it tonight, but hopefully tomorrow or sometime this weekend?
00:52dakroneI don't think it will be difficult, just requires reading docs to find out how to do it
00:58kendallbuchananQuick question: I'm making a leiningen library, in which I'd like to bind the contents of a file in "resources" to a local var, and then access that var's value from a project depending on the library.
00:58kendallbuchananBasically, I want to bind the contents of a file to a var at compilation, not runtime. Any thoughts?
01:01gdevput the slurp in clojure file that has to be AOTd ?
01:03kendallbuchananyeah
01:03dakronebabu`: actually, this looks pretty easy, so I'm hoping to have it done by tomorrow, the hardest part will be testing it
01:04kendallbuchananI'd like a macro like "defcontents", or something: (defcontents my-file "./file.txt"), and my-file would reference the contents of "file.txt"
01:05kendallbuchananor, is there a way to expose the "resources" directory of the library to the hosting program?
01:05kendallbuchananthat'd be another solution, I suppose
01:06gdevand this library has to have the contents of it at compile time to do its job?
01:07kendallbuchananthe program needs access to the contents of a file contained in the library's "resources" path
01:07gdevstill, I think defcontents could be a normal function in a namespace that gets AOT compiled
01:07kendallbuchananI'm unfamiliar with AOT… any constructs I should look up?
01:08gdevstands for ahead of time compile
01:09gdevin your project.clj you can specify what needs to be compiled
01:10kendallbuchananah, it's a compilation setting, then?
01:11kendallbuchananOkay, I think I understand now… thanks!!!
01:12gdevno problem =) glad i could help
01:14dissipatewhen is the entire java standard library going to be ported to pure clojure?
01:15gdevAugust 13 2016
01:15mischovAnd not a minute earlier.
01:16dissipategdev, sweet
01:16callenmischov: nor later. A wizard's grimoire arrives precisely when it means to.
01:16dissipatemischov, if the entire java standard library was ported to clojure, no more calls to java (excepting for 3rd party libs)
01:16dissipatethink of how great that would be
01:17mischovIt seems like it might be a tad bit slower.
01:17callenevery new person says that.
01:17callenthen they learn not to care and move on.
01:18dissipatecallen, we shouldn't care?
01:19callendissipate: it doesn't really affect the day to day experience of writing Clojure.
01:19babu`dakrone, ok thanks, I can pull the updated version when available and run my program and see if it works.
01:19dissipatecallen, or are you saying a new standard library should be built in pure clojure and completely discard the java standard library?
01:20gdevclojure in clojure is just a fantasy dreamed up by people who were just wanting to do web programming anyway
01:20dissipatecallen, but every call to a java library function is a call that causes side effects. isn't the goal to get rid of side effects?
01:21callenthe goal is to write nice software in a sane way.
01:21callennot to engage in a religious crusade against flipping bits.
01:21callenbits are gonna get flipped, one way or another.
01:22dissipatecallen, you have never been burned by side effects in the java libs?
01:24callendissipate: I roast people that ask too many questions over a spit.
01:24dissipatehow rude
01:25mischovbear with him..
01:25callendissipate: but more seriously, as somebody who used to do CL before, the degree to which I am impacted by side effects in libraries, Java or otherwise, is much less substantial.
01:25callendissipate: I would advise, "chill, marinate in the parens for awhile, and enjoy" before launching any crusades.
01:25gdevC-x M-c M-butterfly is how I flip bits
01:26callengdev: like any civilized person.
01:26callendissipate: you'll find something much more important to dislike than that Clojure is hosted in the JVM and uses Java libraries in some cases.
01:28dissipatecallen, no, i'm glad the java libs are available. but i figured it would be good if clojure could escape the java ecosystem entirely some day.
01:28callendissipate: a Clojure-on-the-LLVM project some day could be cool. I'm not really sweating it. 99% of what I do is server-side.
01:28callenwell, server-side or in a web browser.
01:28dissipatecallen, actually, right now i dislike the fact that clojure isn't a replacement for scripting languages
01:29callenit's served fine for me there.
01:29mischovClojurescript+node?
01:29callenmischov: some people do that. Prismatic used to do that (inadvisedly) on the backend, lol.
01:30callenthey use the standard backend tooling now.
01:30mischovdissipate: There are a number of clojure projects targeting other ecosystems. Take a look around for clojure in python, c, etc, or even clojure in clojure
01:32dissipatemischov, have you tried clojure on .NET?
01:33mischovCan't say I have.
01:52gdevi've yet to meet anyone who uses clojure on the CLR
01:53gdevi was tempted to try it out just to say i did it, but then I remembered I had a dentist appointment
02:21[Neurotic]Newb clojure q - looking at different testing libs. Anyone got one they love way more than another? Looking at Midje it seems quite nice. Opinions?
02:22winkseemed nice to me as well :)
02:23[Neurotic]ringingf endorsement ;)
02:28callen[Neurotic]: I prefer clojure.test
02:30[Neurotic]how come?
02:30[Neurotic]the repl support in midje seemed to sell me
02:44s4muelOh, this chat again.
02:45[Neurotic]heh yeah
02:45[Neurotic]sorry ;)
02:47s4muelNo, it's quite alright. I am still on the 'new' side of Clojure and expectations works for me so far.
02:50cgaganyone seen "peerUri is undefined" when trying to use the clojurescript browser repl?
02:51[Neurotic]ah nice and minimal
03:02futileyo dawg
03:02futilei herd u like programming languages so i put a programming language in your programming language so you can program while you program
03:02futile[Neurotic]: yeah expectations is pretty sweet
03:25dissipatewhat is the difference between a 'symbol' and a 'special form'?
03:25TEttinger,(class :whatamI)
03:25clojurebotclojure.lang.Keyword
03:26TEttingerdissipate, good question
03:26TEttingerI kinda would think a symbol is something like the names in let bindings, or the name after def or defn. I'm probably wrong though.
03:27amalloydissipate: they're pretty big difference: they're not at all alike. a symbol is basically a name, often used to refer to an object of some kind, or to represent the program's source code
03:28amalloywhereas a special form is like a primitive operator of the language: "let" and "fn" are two examples, as they're "function-like things" that are actually implemented as compiler specials
03:29amalloywe can compare to java, by a somewhat questionable analogy: in the expression "int x = 5 + 2;", int and x are a little like symbols, and = and + are like special forms
03:31dissipateamalloy, so they are clojure's 'built ins'?
03:32cgagyep
03:32dissipatei'm looking here: http://clojure.org/special_forms
03:32amalloyyes. there are a smallish number of them, but of course it's a little nebulous what counts
03:32dissipatedoesn't seem to be too many
03:33amalloydissipate: that's typical of a lisp
03:33dissipateand it has been rigorously proven that these make clojure turing complete? i'm assuming so. :D
03:33amalloydissipate: it's been rigorously proven that just (fn ...) makes a language turing complete
03:34cgagthat's the beauty of it, so many things you need primitives for in other languages you can do as macros in lisp
03:34dissipatecgag, i haven't gotten to macros yet. how do the special forms relate to macros?
03:35cgagin most other languages, something like "or" is built into the language
03:35amalloydissipate: macros act a lot like special forms, but are written by you instead of rich
03:36cgaga = b || c
03:36RaynesLisp is fanntastic.
03:36amalloyyou can think of them as a little like compiler extensions, except instead of hideously hairy they are pretty simple
03:36cgagyou can't write || yourself because anything you write yourself evaluates it's arguments right away, and || is supposed to short circuit
03:36dissipatecgag, yes, and?
03:37cgagwith macros, you can control when arguments get evaluated, so you can just write or as a macro on top of if
03:38dissipatehmm, i don't see '||' in the special forms list
03:38amalloydissipate: in clojure, (and true (/ 10 0)) doesn't break (because and short-circuits as you'd expect), but it doesn't have to be a special form like it would in, say, ruby
03:38dissipateis it a standard macro?
03:38cgagit's "or" i nclojure
03:39cgagit's not a special form, it's just a macro in the standard library
03:39amalloyinstead, or is written in clojure as (defmacro or [x y] `(if-let [x# ~x] x# ~y))
03:39amalloyyou don't need to worry about *how* that works, the key point is just that you can write it inside the language instead of as part of the compiler
03:39amalloy(and of course that's a simplified version of or that only accepts two args; the real one takes arbitrarily many)
03:40dissipatethat's pretty wild
03:40dissipatethis is a wild language
03:41amalloyi just noticed i accidentally switched from and to or partway through. hope the illustration still worked
03:42dissipateamalloy, how much contention is there over the selection of the special forms? certainly not everyone agrees on what those should be?
03:42amalloywellllll, i'm not sure what you mean. nobody gets to contend, because rich already picked them to build the language from
03:43dissipateamalloy, right, but there are many other flavors of lisp, no?
03:44amalloyah. yes, that's true, and they don't all have identical special forms. but there's a lot in common
03:44dissipateit's interesting that there are so few
03:46TEttingerdissipate, there's a famous paper that kinda lays out the basics needed to implement lisp. can't remember the name.
03:48cgaganyone seen "peerUri is undefined" when trying to use the clojurescript browser repl?
03:49TEttingercgag, I'm afraid I don't yet use clojurescript.
03:50amalloyTEttinger: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.111.8833&rep=rep1&type=pdf ?
03:50TEttingerdissipate, http://www-formal.stanford.edu/jmc/recursive.html this paper. it's a little complex in parts, but it's amazing that the language can be defined with such a small set of forms
03:52TEttingeramalloy, did we link to the same paper?
03:52amalloyi won by two seconds
03:52amalloyi was trying to find the paper you mentioned, so it's not surprising it's the same
03:52TEttingerheh
03:53TEttingerI was wondering if the PDF is better-formatted than the HTML version
03:53cgag'night people, welcome aboard dissipate
04:18andyfingerhutI am trying to understand how core.clj in the Clojure source code can require clojure.java.io, which seems to be compiled later in the build. Is it difficult to explain how that works?
04:19kralany company here that is looking for a wannabe clojure programmer? :)
04:23amalloyandyfingerhut: i don't know what you mean by "later in the build". the compiler evals 90% of clojure.core, recurses into clojure.java.io at the request of clojure.core, and then goes back to clojure.core
04:24amalloyie, compiling a file isn't an atomic operation, and it can be interrupted to go compile another one partway through
04:25andyfingerhutamalloy: Don't be surprised if I am missing something very basic here. If you build Clojure source code using 'ant', for example, the build.xml file invokes the compiler on a sequence of namespaces that starts with clojure.core, and much later in the list it explicitly calls out clojure.java.io as well. Is that clojure.java.io perhaps unnecessary?
04:26amalloywelllllll, i'm not so sure about that part
04:27andyfingerhutI guess I can try an experiment to see.
04:27amalloyit may be the case that Compile/main needs to be passed a list of all namespaces that will be turned into classfiles
04:28amalloywith other namespaces that are required being only "temporarily" compiled
04:29amalloybut i think it's probably the case that you could omit some of those args and they would still be compiled
04:31andyfingerhutDeleting the occurrence of clojure.java.io from that list of namespaces in build.xml causes the ant build to fail when it reaches clojure.java.shell (or near there), probably when it tries to do a :use of clojure.java.io.
04:36andyfingerhutamalloy: Do you have a technical meaning of "only temporarily compiled" in mind?
04:37andyfingerhutamalloy: e.g. a compilation that does not cause .class files to be written to disk, perhaps?
04:37amalloyandyfingerhut: i meant in the way that compilation happens when you're not doing AOT: just to classes defined in memory via the DynamicClassLoader
04:44hiredmanthat seems unlikely
04:45andyfingerhuthiredman: Was that in reference to something I said?
04:50hiredmanto amalloy's explanation, because non-transitive aot is something people have wanted for a long time
04:51hiredmanbut I guess that isn't really non-transitive aot because it is still broken
04:52amalloyyeah, i think it's pretty clear that's not what's going on, just from andyfingerhut's one experiment. if it were, the compiler would work as usual on other files but not output a .class for clojure.java.io
04:57turbopapehi everybody,
04:57hiredmanI suspect it is a classloader issue, the compiler is generating classes using a dynamic classloader, but once compilation finishes the classloader is popped before the next namespace is compiled
04:58turbopapewhere is the link for lighttable 0.5? I only find the linkg for .4.11,
04:58turbopapeand whenever I hit update It tells me that I am on the last version ...
04:59turbopapeAh, I actually needed to refresh my browser...
04:59turbopapenever mind ...
05:29NeedMoreDesuI've written fast version of lazy-shuffle on vectors. http://www.everfall.com/paste/id.php?slhnb97yha7q
05:30NeedMoreDesuSad story is, it's not that lazy if you need to get vector first lol.
05:38NeedMoreDesuWow thats odd. Why my (vec (lazy-shuffle ...)) works 8 times slower that (vec (list (lazy-shuffle ...))) ?
05:38TEttingerNeedMoreDesu, that will blow the stack.
05:39TEttinger(on large collections)
05:39TEttingeryou are recursing without using an explicit recur, and clojure will just go on creating call frames until it blows the stack
05:40NeedMoreDesuIm not recursing, it's lazy collections.
05:40NeedMoreDesuIt wont blow stack.
05:40TEttinger(defn lazy-shuffle... (lazy-shuffle
05:40NeedMoreDesu(lazy-seq (lazy-shuffle ..))
05:41NeedMoreDesuthat makes difference
05:41TEttingerok, didn't see that part
05:41TEttingerI've always been nervous about recursion on JVM
05:41NeedMoreDesuI found out why (vec (list ..)) is faster lol
05:42TEttingerI'm curious. pop?
05:43NeedMoreDesuhttp://clojuredocs.org/clojure_core/clojure.core/subvec
05:43NeedMoreDesusubvec is O(1)
05:43NeedMoreDesuSo I think pop is O(1) too
05:44NeedMoreDesupersistent vectors is just awesome thing.
05:47andyfingerhutpop on vectors is O(log n), but such a nice fast O(log n) that only a theorist should quibble between that and O(1).
05:47NeedMoreDesulog32, afaik
05:47andyfingerhutpop on vectors doesn't use the same implementation that subvec does.
05:48NeedMoreDesuIs it faster?
05:48hyPiRionthan what?
05:48NeedMoreDesuthan subvec.
05:49andyfingerhutThe O(log n) pop on vectors is asymptotically slower than O(1) subvec for large enough vectors. However, subvectors are not quite first-class citizens in the Clojure implementation today -- there are funky limitations on what you can do with subvectors
05:49NeedMoreDesuOh.
05:50NeedMoreDesuSo it's faster to use subvectors in this case?
05:50andyfingerhutSeveral JIRA tickets open for the limitations on subvecs, if you are curious.
05:51andyfingerhutThere could be constant factors hidden in the O(1) vs. O(log n) that still make pop faster than subvec. For that you'd have to do some benchmarking to find out.
05:54NeedMoreDesuResults looks pretty much same.
05:55andyfingerhutThat doesn't surprise me. I suspect they both usually allocate about the same amount of memory, which probably dominates the run time. Not much computation needed for those operations.
05:56TEttingerhow about ##(sort-by #(rand-int -1000 1000) [:a :bb :ccc :dddd])
05:56lazybotclojure.lang.ArityException: Wrong number of args (1) passed to: sandbox80477$eval85003$fn
05:56TEttingerhow about ##(sort-by (fn [] (rand-int -1000 1000)) [:a :bb :ccc :dddd])
05:56lazybotclojure.lang.ArityException: Wrong number of args (1) passed to: sandbox80477$eval85014$fn
05:56hyPiRionheh.
05:56hyPiRion,(sort-by (fn [_] (rand-int -1000 1000)) [:a :bb :ccc :dddd]) ; it is
05:56NeedMoreDesuSometimes pop is faster, sometimes subvec. Well, I guess it's ok to use pop.
05:56clojurebot#<ArityException clojure.lang.ArityException: Wrong number of args (2) passed to: core$rand-int>
05:57andyfingerhutI'd recommend going for pop, to avoid the corner cases you might otherwise hit with subvectors.
05:57gvickersHowcome ,,(= (keys {'foo "baz" 'bar "baz"}) ['bar 'baz])
05:57gvickersis false
05:57NeedMoreDesuTEttinger but it's not lazy.
05:57andyfingerhutNot so much bug corner cases, but feature-not-yet-implemented-in-Clojure corner cases.
05:58gvickersmeant for the vector to be ['bar 'foo]
06:00NeedMoreDesugvickers: it's not really good idea to trust in order of keys in hash-map
06:01andyfingerhutgvickers: That and in your example the keys are 'foo and 'bar, not 'bar and 'baz, but yeah, what NeedMoreDesu said, unless you use a sorted-map, or sort the result of keys.
06:03NeedMoreDesu(keys (sorted-map 'foo "baz" 'bar "baz")) => (bar foo)
06:03NeedMoreDesuStill not ordered in that way it is written, but at least its the same each time it's launched.
06:04gvickersNeedMoreDesu: thanks, I think im going to try every? contains? {.... instead. forgot hashmaps are not sorted :p
06:11TEttingeribdknox, it isn't in the announcement, but were themes removed from 0.5 of light table?
06:14agumonkey hello
06:14agumonkeyi'm having issues with ordering in sets
06:14agumonkey(map (fn [e] e) #{:a :b :c :d})
06:15agumonkey=> (:a :c :b :d)
06:15TEttingersets are unordered.
06:15TEttingeryou want a sorted-set
06:15agumonkeyso map f set will always be potentially 'random' ?
06:15TEttinger,(map (fn [e] e) (sorted-set :a :b :c :d))
06:16clojurebot(:a :b :c :d)
06:16agumonkeyTEttinger: aight thanks
06:16TEttingeralso, sorted-set-by
06:16TEttingerthat one is handy for different sort orders
06:16TEttingeryours is alphabetical now
06:16andyfingerhutOr use regular sets, but before doing things like map on them, sort the elements with the function sort.
06:16TEttinger,(map (fn [e] e) (sorted-set :a :aa :c :d))
06:16clojurebot(:a :aa :c :d)
06:17TEttingerandyfingerhut, that too
06:18agumonkeyis there a syntax literal that I can use with `into` ?
06:18agumonkeyor is (apply sorted-set existing-unordered-set) idiomatic enough (if at all) ?
06:19TEttinger,(into sorted-set (range 2 5))
06:19clojurebot#<ClassCastException java.lang.ClassCastException: clojure.core$sorted_set cannot be cast to clojure.lang.IPersistentCollection>
06:19andyfingerhutThere is no literal syntax in Clojure for sorted sets or maps.
06:19TEttinger,(into (sorted-set) (range 2 5))
06:19clojurebot#{2 3 4}
06:19hyPiRion^
06:19TEttingerthat's as close as it gets
06:20agumonkeyclose enough
06:20hyPiRionalso, in case you need
06:20TEttingerbut regular sets sorted as needed also work
06:20hyPiRion,(into (sorted-set-by >) #{2 3 4 5})
06:20clojurebot#{5 4 3 2}
06:20agumonkeythanks
06:30ciphergothwould you use clojure.async in a live commercial application?
06:31ro_stprobably :-) be nice for it to go out of SNAPSHOT first
06:31hyPiRionno, as there is still no official version out.
06:31ciphergoth*nods*
06:34hyPiRionApart from that, I'd be all over it I assume
06:35ciphergothit is very impressive!
06:35ciphergothmaking it play nicely with aleph could be annoying
07:04muhoowhy would you use both in a single app?
07:33muhoohmm, how long does memoize keep stuff around?
07:34mpenetforever
07:34mpenetcore.memoize has caching strategies
07:34hyPiRionuntil you discard the function
07:43muhooah i see, i can set it
07:44muhoogetting tired. now i'm trying to figure out how to nested destructure stuff, i.e.
07:45muhooi have a ring req i want to take one in and get params out, like (defn foo [{:keys [{:keys [bar baz] :as params} headers] :as req}] foo)
07:46muhooso basically pull out the params and headers, but also pull out the individual params as their names
09:12[Neurotic]seancorfield: you awake?
09:30jamiiI remember reading something about capturing repl interactions and reusing them as regressions tests but I can't for the life of me find it again. Does anyone know what I'm talking about?
09:33jamiiAha - https://github.com/cgrand/replay
09:45muhoo[Neurotic]: i doubt it. it's 6:30am here
09:45[Neurotic]it was always possible ;)
10:02edw,(parition 2 '(1 2 3 4 5))
10:02clojurebot#<CompilerException java.lang.RuntimeException: Unable to resolve symbol: parition in this context, compiling:(NO_SOURCE_PATH:0:0)>
10:02edw,(partition 2 '(1 2 3 4 5))
10:02clojurebot((1 2) (3 4))
10:02edwDoes that result concern anyone? It doesn't seem to match the docs.
10:04edwOK, it does match the docs.
10:04edwOr the examples…
10:05jkkramer,(partition-all 2 '(1 2 3 4 5))
10:05clojurebot((1 2) (3 4) (5))
10:05vijaykiranedw: what you are looking for is partition-all
10:05vijaykiranah - ask jkkramer said
10:06edwAh, thank you. I was doing (parition n n nil coll), which is a bit of a PITA.
10:24jtoy&(doseq [x [1 2] i (take 2 (range))] (println i))
10:24lazybot⇒ 0 1 0 1 nil
10:24jtoywhy does thta print 0 1 0 1 and not just 0 1 ?
10:25ToxicFrog...how does that resolve x and i?
10:25ToxicFrog&[x i]
10:25lazybotjava.lang.RuntimeException: Unable to resolve symbol: x in this context
10:26ToxicFrogOh, doseq takes a binding-form.
10:26ToxicFrogI thought it was another dorun variant.
10:27ToxicFrogjtoy: because it iterates over the product of both lists.
10:27ToxicFrog&(doseq [x [1 2] y [3 4]] (println [x y]))
10:27lazybot⇒ [1 3] [1 4] [2 3] [2 4] nil
10:27jtoyi just want to have an i for each item in x
10:27jtoyhow would i do that with doseq?
10:28agumonkeymaybe zip
10:28ToxicFrogSo, first it iterates over the first value of x (1) and all values of i, then over the second value of x and all values of i - so each value of i shows up twice.
10:28ToxicFrogjtoy: what do you mean by "an i for each item in x"?
10:28jtoyso if i have x [ 34 78 99] i want to have an i that prints out 0 1 2
10:28ToxicFrogEr
10:29jtoyjust the step I am at in the collection
10:29agumonkeyjtoy: always 0 1 ... ? or any value ?
10:29ToxicFrogso (take (count x) (range)) then?
10:29jtoyyes, which is what I have earlier, but i dont want the product
10:29cmajor7jtoy: (map-indexed (fn [i xi] ...) [34 78 99])
10:29ToxicFrog&(let [x [5 8 12 4]] (take (count x) (range)))
10:29lazybot⇒ (0 1 2 3)
10:29agumonkeycmajor7: +1
10:30ToxicFrogjtoy: "don't want the product"?
10:32jtoyToxicFrog: you said earlier it itterates over the product of both?
10:32tbaldridgednolen: ping
10:32jtoyi want to iterate through random collection with doseq but also know the position i am at
10:33cmajor7jtoy: why doseq? why not map-indexed?
10:33cmajor7jtoy: that does exactly that
10:33jtoycmajor7: I am writing out a file and i need to put the line number
10:33jtoy(doseq [line lines] (write lines and line number))
10:33atyzThis might be silly - is there an easy way to return a realized map of a datomic entity with sub-entities (I have isComponent true). I'm in the midst of writing a function to realise them all and it feels like there should be an easier way
10:34jtoycmajor7: is there a better way?
10:34cmajor7jtoy: (map-indexed (fn [n line] (write (str "n:" line))) lines)
10:34ToxicFrogjtoy: doseq does, yes. The answer is not to use doseq.
10:34scgilardiatyz: does "touch" get close?
10:34cmajor7(map-indexed (fn [n line] (write (str n ":" line))) lines)
10:35jtoycmajor7: ok, I see, thanks
10:35atyzscgilardi: touch only realises the primary entity - not it's children
10:38scgilardiI think the intent is for it to recursively realize isComponent children. (from: https://groups.google.com/forum/#!topic/datomic/wsyvv8BCQw0 ) not sure why it wouldn't be in your case.
10:41cmajor7atyz: are your "refs" are "isComponent" or something else?
10:41atyzscgilardi: the problem is that it realises them as a DatomicEntityMap so if I want to do any manipulation to any of the subcomponents it won't allow me to
10:42atyzcmajor7: isComponent true on all in question here
10:42cmajor7usually [entity has "refs"], those "refs" should be "isComponent" to realize on (touch entity)
10:42atyzcmajor7: basically I don't want to have to use my datomic entity names in my application code
10:43cmajor7atyz: why names?
10:43cmajor7atyz: you only need id(s) to -> touch ..
10:44cmajor7i.e.
10:44cmajor7(defn entity [id]
10:44cmajor7 (d/entity (db-now) id))
10:44cmajor7(defn touch-id [id]
10:44cmajor7 (d/touch (entity id)))
10:45cmajor7this of course has a "db-now" hardcoded.. if you need to touch with different db values, pass those as well..
10:45atyzOh sorry - miscommunication - the touching part works fine if you're trying to just print the data or access it. however I need to turn {:source/name "something" :sub {:sub/meh "somethingelse}} into {:name "something" :sub {:meh "somethingelse"}}
10:46lycrgs678I am new to clojure. What's the most common framework used for webapps? Noir?
10:46atyz** :source/sub
10:46cmajor7lycrgs678: compojure
10:46lycrgs678thank you cmajor7
10:46cmajor7atyz: you mean convert to "no datomic" namespace map?
10:47atyzcmajor7: yes
10:48cmajor7atyz: yea.. looking at my code from some time ago, I have a function that does that :)
10:48atyzcmajor7: i would love it if you would let me look at it? :)
10:48cmajor7atyz: but it is a bit logic specific
10:49cmajor7atyz: trying to see if it can be cleaned up to show you. it is for a customer.. so not quite open source..
10:50atyzcmajor7: ahh - it would be appreciated if you could
10:50atyzare you currently using your fully qualified datomic names in your code?
10:51cmajor7atyz: you mean the attribute names as they are in the schema?
10:51atyzcmajor7: yes, sorry
10:52cmajor7atyz: yes, I do, but I do the conversion, since I pack the data in protobufs before sending it elsewhere
10:52jballancanyone have advice on using npm/bower libraries with Clojurescript?
10:53cmajor7atyz: looking at the function, I wish I would write it now as I know a Clojure and Datomic better, otherwise I don't like my own code from 7 months ago :) it'd be easier if you give me a result of the query you want converted to a "no namespaced" map
10:56dnolentbaldridge: pong
10:56tbaldridgednolen: in CLJS if I have a predicate (active? foo) is negating with not going to slow things down a ton? (not (active? foo))
10:57tbaldridgeor can I type hint that with ^boolean to speed things up?
10:57dnolentbaldridge: you don't need to negate, you can just type hint ^boolean
10:58dnolentbaldridge: the only time you might negate is you're checking for nil
10:58dnolentbaldridge: (if x ...) where x might be nil will emit a truth call. so (if-not (nil? x) ...) is better
10:58tbaldridgeand (not (nil? x)) should be hinted?
10:59tbaldridgewell here's the actual code: (and (not (nil? buf)) (pos? (count buf)))
10:59dnolentbaldridge: oh you never need to hind cljs.core predicates they already are
10:59dnolentbaldridge: protocols don't support type hints in Clojure is the problem with protocol methods that return boolean values
10:59dnolentbaldridge: yes there's not way around that - but no need for type hints there.
11:00tbaldridgeok, so I should be good then. I'm re-writing core.async CLJS channels today, so far I've probably cut 25% of the code. So this is looking good.
11:01dnolentbaldridge: awesome! you can always look at the simple output to know if you're doing your boolean stuff correctly
11:01dnolentbaldridge: if it's right you won't get if((function() { ... }()) { ... }
11:01tbaldridgednolen: kk
11:01dnolentbaldridge: or if(cljs.core.truth_(x)) { ... }
11:08wakeuphi all
11:09glosolihey
11:09wakeupI apparently have a LazySeq, and another seq, and I want the
11:09wakeupelements in seq that do not appear in LazySeq?
11:10wakeupclojure complains lazyseq doesn't support contains?
11:10wakeuphow do I convert my lazyseq to a seq I can call contains on?
11:11arrdemwakeup: do you have bounds on the lazyseq's length?
11:11wakeuparrdem: its the result of map and concat so I'd say yes, its not infinite
11:12arrdemwakeup: I mean you can just (apply list <expression>)
11:13arrdemwakeup: but I contend that you should be able to perform a constant space difference operation by sequentially resolving the items of the lazy seq and testing them for membership in the hard seq.
11:13wakeupAh
11:13wakeupI uset set and difference and it works
11:17tgoossenshow do i get the output of pprint written into a file?
11:17arrdemtgoossens: you can bind *out* to a file object for one..
11:18tgoossensjmm
11:18tgoossens*hmm
11:19arrdemso (binding [*out* (File. "~/my/path.dump")] (pprint <expr>))
11:19arrdem,*out*
11:19clojurebot#<StringWriter >
11:19arrdemyep. that's the var.
11:19wolfesIs there a way to get every namespace in a lein project to (require '[clojure.repl/pprint :as pp])
11:20wolfesi figured out how to do it on init for the first namespace
11:20wolfesbut it doesnt seem to carry over for other ns
11:20arrdemwolfes: no and there shouldn't be one.
11:20arrdemwolfes: you _can_ tell lein to automatically (require) some namespace when kicking off a repl
11:21wolfesrepl-options init :)
11:21tgoossensiit doesn't write anything to the file though
11:21tgoossens(binding [*out* (File. "~/my/path.dump")] (pprint <expr>))
11:21tgoossensoops
11:22tgoossens(binding [*out* (java.io.FileWriter. (java.io.File. "graph.txt"))] (pprint "hello"))
11:22arrdemtgoossens: (-> *out (.flush) (.close))?
11:23tgoossensmy god
11:26jkkramer(with-open [f (clojure.java.io/writer "graph.txt")] (binding [*out* f] (pprint "hello")))
11:26jkkramer…i think. that's untested
11:26tgoossensit works though...
11:26arrdemjkkramer: so what you're really saying is that like me you're spitting sexprs from the hip with not enough coffee
11:27arrdem,0xC0FFEE
11:27clojurebot12648430
11:27llasram,0xDECAFBAD
11:27clojurebot3737844653
11:27jkkrameryeah, too bad irc doesn't have paredit
11:27arrdemI kinda want to write an erc script that supports diff messages...
11:28arrdemso I can retroactively ammend what I've previously said :P
11:35hyPiRion,36rClojurebot
11:35clojurebot1279886746883501
11:36arrdemhyPiRion: why 36? I'd think that 26 or 52 would be in order.
11:37hyPiRion,26rClojurebot
11:37clojurebot#<NumberFormatException java.lang.NumberFormatException: For input string: "urebot">
11:37hyPiRion,52rClojurebot
11:37clojurebot#<NumberFormatException java.lang.NumberFormatException: Radix out of range>
11:37hyPiRionthat's why
11:37arrdemI see the error, I don't follow the why.
11:38cmajor7atyz: (defn map-walk [m] (if (map? m) (reduce (fn[a [k v]] (assoc a (-> k name keyword) (map-walk v))) {} m) m))
11:38cmajor7make sure there are no duplicates in names of different namespaces on the same level, since it is going to ignore all but last
11:38cmajor7{:some/one 21 :every/one 42} => {:one 42}
11:38atyzcmajor7 thank you!
11:39hyPiRionwell, base 36 is the highest supported with the r-format. 26 isn't enough because we start off with 0123456789, then the letters
11:39TimMcarrdem: 36 is the max radix for Java parseint.
11:39TimMcYou get some prefix of 0-9a-z.
11:39hyPiRionit's like, hm
11:40TimMc(Somehow I missed that hyPiRion had just explained it.)
11:40hyPiRion,(apply str (concat (range 10) (take 26 (map char (iterate inc (int \a))))))
11:40clojurebot"0123456789abcdefghijklmnopqrstuvwxyz"
11:40TimMcOh, and 52 (or 62) isn't an option because the format treats upper and lower case identically.
11:41arrdemTimMc: ah OK I didn't know there was an upper bound on the reader radix or that it was case insensitive :P
11:42TimMc&[36ra 36rA]
11:42lazybot⇒ [10 10]
12:24tbaldrid_dnolen: so, on my box, with the new dispatcher and channel code, I can put 1 mil messages into a (chan 1) in 3600 ms. With a (sliding-buffer 1), that drops to 328ms
12:25bbloomtbaldridge: but how many messages are being dropped that way?
12:25dnolentbaldridge: what changes did you make to the dispatcher?
12:25dnolentbaldridge: note I think my old tick idea was not good one because it ruins reasoning about buffer sizes
12:25tbaldridgednolen: just the tick based ones you discussed. I added a unbounded ring buffer for the task queue, and then we run a max of 1024 tasks on each dispatch
12:26bbloomtbaldridge: oh nevermind, ignore my comment. misread you
12:26TimMcDo the size limits on the buffers guarantee an exact size, or a minimum size?
12:26dnolentbaldridge: yes so I said earlier the tick idea is not good, you can lose control of buffer semantics
12:26tbaldridgebbloom: that's why the sliding buffer is slower, it just testing one side of the buffer
12:26bbloomyup gotcha now
12:26tbaldridgednolen: eh, let me paste my code and see what you think
12:26dnolentbaldridge: so now a buffer of size 5000 will never do what it's intended to do
12:26coventryWhat's the closest clojure has these days to CL conditions and restarts? It looks like error-kit is no longer used?
12:27tbaldridgednolen: this is the new dispatcher code, it's not the same as the code you had https://gist.github.com/halgari/6321034
12:29tbaldridgeand that has a bug....well it's still WIP
12:30dnolentbaldridge: so try this, remove the dispatcher code and try with with (chan 1024) and (chan 5000)
12:30dnolentbaldridge: I'm just not convinced about putting more logic in the dispatcher anymore
12:32tbaldridgebut think of the logic, every time we have a put/take match inside a channel we have to run the dispatcher. so (chan) will always dispatch. So that code will be super slow without a better dispatcher.
12:32dnolentbaldridge: this is not a real problem
12:33dnolentbaldridge: if somebody doesn't want to be dispatching all the time use a larger buffer size
12:33dnolentbaldridge: also I did some numbers about common use cases of (chan) like in the interactive case, mouse input
12:34dnolentbaldridge: it would take a pipeline 300 channels deeps in modern browsers before you would have a problem w/ (chan) and mouse input
12:34dnolenif you mouse channel pipeline is 300 channels deep something needs refactoring.
12:35tbaldridgeso what's the penalty of using a more complex dispatcher? time to do some tests.
12:35dnolentbaldridge: the penalty is (chan N) where > N 1024
12:35dnolentbaldridge: that's a show stopper in my opinion
12:36tbaldridge(chan N) where > N 1024 ?
12:36dnolentbaldridge: you will want a fat chan if you're creating events via data, 1024 is too small
12:36supersymcoventry: I don't know about those, the only thing that springs to mind is https://github.com/MichaelDrogalis/dire
12:37supersymit has some example for self-correcting code
12:37dnolentbaldridge: if you have custom dispatch code you're breaking how buffered channels works, whatever N is pick is now the clamp, instead of the user defined buffer size
12:38tbaldridgeNo, with my code the semantics stay the same, we just simply run as many tasks as possible before dispatching again. So we move the task queue from the browser into user code.
12:38dnolentbaldridge: hrm, looking again
12:38tbaldridgeNew dispatcher/run functions are always put at the input of the FIFO queue.
12:39dnolentbaldridge: ok how does this not break (chan) ? does that mean I need 1024 mouse events before another go block gets to run ?
12:39dnolena go block which might be consuming those events?
12:41dnolentbaldridge: note the browser will emit at most ~160 mouse events a second
12:43tbaldridgednolen: nope, it doesn't break. the mouse event put!s into the chan and ends up in the puts queue, pending takes are dispatched, if there are no pending takes, then the mouse events pile up in the take queue.
12:44tbaldridge*pile up in the put queue
12:44coventrysupersym: Thanks, looking now.
12:44dnolentbaldridge: dispatched? but won't it just end up in the dispatch queue instead of running immediately?
12:44bbloomfor some reason my irc client has changed tbaldridge's handle from red to green, which now matches dnolen's, making it impossible to follow this discussion :-)
12:45dnolentbaldridge: ok sorry I reading more closely now
12:46tbaldridgethey don't run immediately with the old code either. the callback you get back from a impl/put! is the same callback you handed to impl/put! not the take's callback
12:46tbaldridgeso dispatch is always run against "the other guy"
12:46dnolentbaldridge: I see now, you're accounting for more stuff that might appear between dispatches
12:46tbaldridgeright
12:47dnolentbaldridge: hey pretty cool :)
12:47dnolentbaldridge: if the ring buffer is 32 how could you ever reach 1024?
12:47tbaldridgeI got one nasty bug to fix, but then I'll throw this all up in a branch and see where what you all think. I've also added .unbounded-unshift that resizes a ring-buffer if it runs out of space.
12:48dnolentbaldridge: ok I get it now
12:48tbaldridgeso each time it runs out of space, it'll double in size
12:48dnolentbaldridge: unbounded-shift was the missing part for me
12:48dnolentbaldridge: looks cool, will try it when you get it up
12:52coventrysupersym: dire looks awesome. I'm more interested in the restart side of the condition/restart system though. Something which will return the full stack at the point an exception occurs, rather than the stack in the catch/finally clause.
12:53dnolentbaldridge: so do the takes/puts in ManyToManyChannel use ring buffers now too?
12:53tbaldridgednolen: yes
12:53dnolentbaldridge: sweet
12:54tbaldridge"ring buffer all the things!"
13:03konr`Is there a protocol for objects that implement toString?
13:04dnolenkonr`: for CLJS?
13:04konr`dnolen: regular CLJ
13:04dnolenkonr`: that would be Object
13:04dnolenkonr`: no protocol
13:05konr`dnolen: hmmm, didn't know of that!
13:05dnolenkonr`: also for equals and hashCode
13:06dnolenkonr`: this means this can only be done in deftype, you can extend-type this stuff
13:06dnolens/can/cannot
13:06supersymcoventry: ok, don't know any that does, soz
13:06dnolenkonr`: doesn't work w/ defrecord since those things are provided for you
13:06dnolen" this means this can only be done in deftype, you cannot extend-type this stuff"
13:06coventrySupersym: no worries
13:11tbaldridgednolen: here's the code: https://github.com/clojure/core.async/tree/tims-optimizations
13:13dnolentbaldridge: I leave some comments (minor boolean related stuff)
13:13tbaldridgekk
13:17bbloomtbaldridge: total nitpick, but there's really no need for "constants" to be IN-ALL-CAPS
13:17bbloomi mean, *everything* is supposed to be immutable, right? :-)
13:17tbaldridgebbloom: but, but, that's the way it's done in C :-P
13:18bbloomtbaldridge: right, but in cleff i had to do COMMUNICATION-IDX to match what you did & i felt dirty :-P
13:18dnolentbaldridge: ok little perf comments added
13:18tbaldridgebbloom: I'm sorry that I make you feel dirty. lol
13:18bbloomtbaldridge: you're forgiven, but only b/c the code is otherwise quite clean
13:19dnolentbaldridge: looks pretty nice, after those changes I'll give it a run around
13:20tbaldridgednolen: kk I'll get it updated
13:22mdrogaliscoventry: I'm around if you need help with it.
13:26wei_how can I make (pr-str (org.bson.types.ObjectId. "5217512f3b7e53472217ea65")) return an EDN-readable format? i.e. #"ObjectId" "5217512f3b7e53472217ea65"
13:27mdrogaliswei_: What datatype do you want it to coerce to in EDN?
13:27wei_a str
13:27stuartsierrawei_: define a new method for print-method.
13:27wei_I'm trying to serialize mongo objects for use in clojurescript
13:28tbaldridgednolen: done
13:31lynaghkdnolen: ping
13:31dnolenlynaghk: pong
13:31lynaghkdnolen: what are your thoughts on Polymer/WebComponents?
13:31dnolenlynaghk: not particularly positive
13:31wei_@stuartsierra could you elaborate a bit? I'm not understanding the print-method example
13:32lynaghkdnolen: yeah, I thought it was something like that (via a few of your tweets)
13:32lynaghkdnolen: is there anything in particular that you think is a bad idea?
13:32stuartsierrawei_: (defmethod clojure.core/print-method org.bson.types.ObjectId [oid writer] …)
13:33dnolenlynaghk: my experience with every UI system just tells me the assumptions present in Polymer are deeply flawed
13:33wei_i see, thanks. does that activate globally?
13:33lynaghkdnolen: there are some usual Clojurist things I'm not a fan of (e.g., implementation inhertance of components), but the general idea of trying to package up reusable components as new tags seems like a sound one to me---at least, it's a continuation of what browsers are already.
13:34lynaghkdnolen: those assumptions being?
13:34dnolenlynaghk: what's the value over jQuery UI or other widget libraries?
13:34lynaghkdnolen: declarative markup; that something lower level is handling initialization for you
13:35lynaghkrather than a shitshow main() method that is tightly coupled to IDs/classes.
13:35patchworkdnolen, lynaghk: From what I have heard of this, the advantage is the nested definition of components
13:35dnolenlynaghk: so you really don't believe Polymer is not going to result in a shitshow?
13:36wei_lynaghk: is this related to your quest for finding the perfect data binding solution for webapps?
13:36lynaghkI'm not sure how I feel about the "bang-on-the-view-model" approach of WebComponents/Angular.js, but I'm not sure what a more functional approach would look like
13:36dnolenlynaghk: this has all been done before, we know what the results look like
13:37lynaghkdnolen: the UI situation on the web right now is a shitshow, and polymer/angular seem like an improvement to me over the defacto main() method approach
13:37dnolenlynaghk: I don't see how Polymer will be an improvement beyond anything surface level
13:37dnolenlynaghk: it solves two small things, but people will still make shitty components
13:37bbloomlynaghk: check out react.js
13:38lynaghkdnolen: you could use some of the good ideas of polymer in conjunction with core.async coordination
13:38dnolenlynaghk: implementation inheritance will be monstrosity
13:38lynaghkdnolen: totally
13:38Anderkentcore.async question: does alts! busy loop until a channel is available? It seems so from eye-balling the code (ioc-alts! never returns nil, always either result or :recur). The docs say it will park though...
13:38dnolenlynaghk: if that's the way the current is flowing - not much you can do about it but I just don't really care that much.
13:38lynaghkbbloom: react.js doesn't seem to have a good story about separating markup from behavior
13:39dnolenlynaghk: also I find the markup parts very suspect
13:39coventrymdrogalis: Thanks.
13:39dnolenlynaghk: does the spec allow you replace w/ whatever you want?
13:39lynaghkdnolen: the notion of being able to create custom tags with their own styling and behavior?
13:40dnolenlynaghk: I mean how flexible is it, is it easy to break components if I add my own attributes, if I embed some subview etc.
13:40bbloomlynaghk: in what way do you want to separate markup from behavior? it strikes me as a strange idea that you even can strictly separate structure from behavior. doesn't behavior require some structure to operate on?
13:40dnolenlynaghk: or is this something they expect people mess up as usual?
13:41lynaghkdnolen: it's certainly more flexible/composable than something like jQuery UI---all of those things expect to get an element that they can totally own and clobber without any thought to composability
13:41jtoyhow does one process a pair of items from 2 collections at the same time?
13:42jtoyso if i had [1 2 3 ] [4 5 6] i could get 1,4 and 2,5 and 3,6 ?
13:42lynaghkbbloom: you definitely need some structure, but you should be able to do that in the HTML and not have to do it in the JS.
13:42technomancy,(map vector [1 2 3] [4 5 6])
13:42clojurebot([1 4] [2 5] [3 6])
13:42bhaumanAnderkent: blocks inside of a go block.
13:42dnolenlynaghk: so then my concern is the value proposition is very small - with some resoundingly bad OO ideas baked in
13:43bhaumanAnderkent: as far as I know it's reactive
13:43lynaghkbbloom: that all of the react.js examples I've seen have lots of HTML-in-strings-in-JS gives me the idea that it'll be very hard to build, e.g., a <tabs showing="idx"> <tab>...</tab> <tab>...</tab> </tabs> kind of component
13:43lynaghkdnolen: I agree with you about the OO ideas 100%
13:44lynaghkdnolen: re: value of building custom tags, it's by far the most composable approach I've seen thus far in the web UI world.
13:44jtoythx
13:44lynaghkespecially w.r.t. collaborating with designers
13:44bbloomlynaghk: there are no HTML-strings-in-JS. they have an *optional* javascript preprocessor that converts XML literals into data construction calls
13:44dnolenlynaghk: I just think it's all very short sighted. Looking forward who cares about the DOM, we need/want to abstract UI components over SVG, Canvas, WebGL
13:45Anderkentbhauman: so from doing it on the repl it seems it doesn't busy loop, but I can't see how that happens from the code. ioc-alts! calls do-alts, which eitehr says 'i read you a value' or returns nil if no channel has anything... ioc-alts! either advances the state machine in the first case, or returns :recur in the latter... Recur just makes the thread loop into ioc-alts! again as far as I can see.
13:45dnolenlynaghk: instead we're gonna get desktop UI thinking all over again, do not want
13:45bbloomdnolen: agree w/ that
13:45lynaghkdnolen: the DOM *is* abstract UI components!
13:45dnolenlynaghk: so how will your Polymer component work in WebGL?
13:45dnolenit won't
13:46bbloomlynaghk: well, only if you allow custom dom elements to be created
13:46dnolenyou'll replicate all the crap for a different surface
13:46patchworkdnolen: Abstracting over SVG, Canvas or Webgl you still need an approach to designing them!
13:46lynaghkpatchwork: yes!
13:46lynaghkdnolen: you mean building out a full UI that renders in WebGL?
13:46jtoyis there a cleaner way to write this: (map first (filter #(= (last %) 1) (map vector candidates results)))
13:46patchworkThe philosophy behind how to design a UI is independent of what it is implemented in
13:46bhaumanAnderkent: you are far deeper into it, than I am. i only know from experience that it doesn't loop. But do you have any luck expanding the go macro
13:46dnolenpatchwork: Polymer doesn't do this
13:47dnolenlynaghk: UI components are processes not what they look like
13:47patchworkdnolen: Right, but how would you do that?
13:47dnolenpatchwork: read my core.async posts
13:47cesparejtoy: well for starters instead of (first (filter you can use find-first
13:47patchworkThe question is: What is the best way to design a UI?
13:47patchworkdnolen: I'll check them out. core.async for UI?
13:47dnolenpatchwork: yep
13:47jtoycespare: that is different
13:47dnolenpatchwork: http://swannodette.github.io/
13:47sjlcespare: it's (map first (filter not (first (filter
13:47jtoyi am mapping out the first item
13:47Anderkentbhauman: that's what I did, and I can't see how it returns control - even though I know it does. Perhaps I should put prints into the expanded form :P
13:48lynaghkdnolen: yes, agreed. So with polymer you can define something like <my-button with="arguments"> and style it independently.
13:48cesparejtoy: sorry misread
13:48dnolenlynaghk: but people are going to write logic that targets DOM
13:48dnolenFAIL
13:48bhaumanAnderkent: did you see the post explaining the state machines?
13:48bbloomdnolen: you can't say that's FAIL, there are different goals
13:48lynaghkdnolen: if you're saying that polymer isn't great because you can't take it and render it in WebGL, that's not something I'm very concerned about.
13:48Anderkentbhauman: yes. That's where my investigation started
13:48AnderkentI saw the ioc-alts! code and said 'wait a moment this busy loops
13:49dnolenlynaghk: that's not what I'm saying
13:49lynaghkdnolen: (also, if you do things correctly I don't see why you wouldn't be able to take the HTML + CSS and write a WebGL renderer)
13:49bbloomlynaghk: seriously though, go look at react.js. it's much more functional than it is OOP, in fact, it's only as OOP as javascript forces on it
13:49jtoycespare: it looks bad to me because i do a transformation, filter, then another transformation
13:49dnolenlynaghk: people are going to deliver what could be reusable logic, but it won't be reusable
13:49lynaghkbbloom: noted, I'll take a deeper look at it
13:49dnolenlynaghk: you can only use it with Polymer
13:49bbloomlynaghk: polymer is yet another smalltalk-legacy MVC OOP mess
13:49bbloomlynaghk: react.js looks kinda OOP & demos poorly b/c it seems like it's similar to what you've seen before
13:49bhaumanAnderkent: well you are inspiring me to finally take a look at it.
13:50Anderkentit's pretty good
13:50Anderkentjust don't start reading large blocks that he pastes in here and there
13:50lynaghkdnolen, bbloom: Again, I'm not 100% sold on polymer---it's just the best concrete thing I'm aware of right now. If you guys can point to other systems (or even whitepapers with pseudocode) I would love to see 'em
13:50bbloomlynaghk: but in reality, it works with *data* & external state. it hydrates instances on demand, memoizes functional rendering output, then incrementally mutates the dom, treating it as an external database
13:50bhaumanAnderkent: I have been a happy incurious, consumber
13:50AnderkentI did that, spent 10 minutes parsing some sophisticated code, and then saw that he goes through it expression by expression below that
13:50Anderkent:D
13:51bbloomlynaghk: the majority of your components are stateless & their instances are not retained in memory except when necessary during rendering
13:51bbloomlynaghk: stateful components are OOP only in the sense that they can respond to events in a traditional manner & have some state. but that state isn't stored in the object, it's stored in a global database & referenced by ID. you can't communicate between components except via parameterization
13:52lynaghkbbloom: don't you think many UI components need state? E.g., selected items in a list?
13:52bbloomlynaghk: yes, i do think that. which is why i like react's approach
13:53lynaghkbbloom: aren't polymer components attributes the parameterization you're describing?
13:53sjlcespare: I
13:53bbloomlynaghk: components are built up of 1) types (which are == the classes of the objects / custom element names) 2) "parameters" which are like arguments to the render function 3) children, which is the result of rendering 4) an optional state json object, which can be used to update params or children during the next render pass
13:53sjl'd probably do something like (for [[c r] (map vector candidates results) :when (= r 1)] c)
13:54bbloomlynaghk: it feels similar to writing a server-side rendering with a templating language, only you can associate state & event handlers with components
13:54sjland use (zip ...) from flatland/useful instead of (map vector ...)
13:54Anderkentbhauman: ah, I'm an idiot. in ioc-alts! I misread a `when-let` for an `if-let`
13:54Anderkentthat's disappointing
13:54bbloomlynaghk: instead of inheritence, you just create lots of small, generally stateless components, which are similar to helper functions
13:54lynaghkbbloom: what triggers re-rendering? Is there a dirty-checking loop like angular, an ordered dependency graph like flapjax, or straight up callbacks on individual properties?
13:55Anderkent.. I'm gonna grab a beer.
13:55tbaldridgednolen: there's a odd race condition I'm working through may not want to test this quite yet.
13:55bhaumanAnderkent: no don't do that it won't help
13:55dnolentbaldridge: ok
13:55bhaumanAnderkent: :)
13:55bbloomlynaghk: it's similar to angular, but where angular diffs the view model, react diffs the views
13:56Anderkentbhauman: going home anyway :P
13:56Anderkentthanks for the help
13:56lynaghkbbloom: I thought the only state was in a JSON object
13:56bbloomlynaghk: it's a transactional model, like clojure. you have a database of components+state, when events fire, things react to them & commit new state. the components can not mutate each other's state nor can they even see the effects of their state changes. after each component gets a chance to react to events, which happen in a synchronous pass, then all the differing state triggers cascading re-renders
13:56bhaumanAnderkent: enjoy, don't think I helped but it was good chatting.
13:56lynaghkbbloom: I do like that react.js and polymer both have TodoMVC entries = )
13:56cesparesjl: jtoy how about (keep-indexed #(if (= (results %) 1) true) candidates)
13:57cesparesjl: jtoy sorry i mean (keep-indexed #(if (= (results %) 1) %2) candidates)
13:57bbloomlynaghk: i think it's extended JSON, like you can have dates in there, just like in angular, you can store anything you can diff
13:57dissipatewhat is the 'best practices' rule of thumb for destructuring expressions? it seems like those can get out of hand
13:57xiaqclojurebot: how do i play with you?
13:57clojurebotHuh?
13:57xiaqclojurebot: $help
13:57clojurebotExcuse me?
13:57xiaqclojurebot: @help
13:57clojurebotGabh mo leithscéal?
13:57bbloomlynaghk: dnolen argues correctly that react & polymer are both DOM-centric, but i think that react's model is a deeply functional approach under the hood
13:57lynaghkbbloom: interesting. I'm going to dig through it and Polymer's TodoMVCs. Maybe a blog post will come out of this.
13:58lynaghkor, god help me, some ClojureScript sketches = )
13:58bbloomlynaghk: dnolen: i've been on-and-off-again working on a underlying-tech-agnostic UI toolkit that has a lot in common w/ react's underlying model
13:58lynaghkbbloom: yeah, the bits of angular/polymer I'm excited about are the DOM integration, not the OO/mutation stuff.
13:59bbloomlynaghk: angular is nice, but you have to write a lot of crazy directive stuff for larger apps & reusable components. react & polymer make modularity the default, but polymer goes full OOP & react goes full memoizing pure render functions w/ a transactional update pass
14:01lynaghkbbloom: interesting summary. Thanks for bringing React to my attention. I'll dig 'round and try to figure out the best ideas to steal for use with cljs
14:02bbloomlynaghk: note that react doesn't bother trying to integrate w/ the dom. there are no actual custom tags reified at runtime b/c there is no value in that. there is no browser-level shadow dom or anything like that
14:02dnolenlynaghk: I also think the initialization stuff is not good
14:03sjlcespare: if results is a vector or somthing that supports effecient acces by index, that will work
14:03dnolenlynaghk: I'm leaning towards a model where widget sitting around in memory never happens, only processes over them that appear or disappear as required which is as it should be in my opinion.
14:03sjlcespare: that also assumes you don't have a candidate, result pair of nil 1
14:04sjlin which case it wouldn't return the nil properly
14:04dnolenlynaghk: basically I'm done w/ the last 8 years of stuff I've done on the web, Polymer is just more of the same to me in everyway.
14:04bbloomdnolen: that's exactly how react works
14:04dissipatednolen, what do you mean you are 'done' with it?
14:04lynaghkbbloom: wahhhh, I'm confused now. There is so much value in a shadow DOM and custom tags
14:05bbloomlynaghk: there is value in custom tags, there is no value in reifying them for the browser to inspect
14:05dnolendissipate: no longer interested in putting any more brain time into that style of programming.
14:05bbloomdnolen: react does not instantiate or retain widgets in memory
14:05lynaghkdnolen: yeah, I know you've been in the space for a while, which is why I'm interested in your opinion on these matters
14:05bbloomdnolen: if you widgets have state, then that state is stored in a global widget-id => state map
14:05lynaghkdnolen: sometimes I need to get pulled by the nose for a while before I can see the light, though = )
14:06bbloomdnolen: if an event is fired, the object is only instantiated to maintain a javascript-style developer experience. it's about as far from OOP as you can actually get. each object is more like a go-loop which responds to a message & keeps it's state as a loop argument
14:06dissipatednolen, the web SUCKS. that's my opinion
14:07dnolenbbloom: yes, I still need to look at React (after grokking ANF ;), I've been thinking about a core.async AppState thing
14:07lynaghkdnolen, bbloom: I gotta run right now though. Thanks for all of the good ideas.
14:07dissipatehow many more language X to javascript compilers do we need?
14:07dnolendissipate: heh, I think the web is awesome, CLJS is a good model to reign in the monster
14:08dissipatednolen, the web is broken as is the industry of 'web programming'
14:09dnolendissipate: not any more than anything I've used - mainstream desktop / server programming looks equally gnarly to me.
14:09dnolendissipate: I think browser stuff aside, the reason people don't like web programming is that people are doing distributed system programming with crappy tools.
14:09bbloomeverything sucks and no one cares!
14:09dissipatednolen, all these highly caffeinated 'brogrammers' who think MVC is an architecture. have you ever seen Uncle Bob's stuff? http://www.youtube.com/watch?v=asLUTiJJqdE
14:09bbloom:-)
14:10winkno software is better than no software.
14:11winkbest quote from puppetconf :P
14:11dissipatednolen, on the desktop you can pick your language, your architecture and whatever else. in the browser, you are trapped with HTML, CSS, javascript. that's bad
14:11patchworkdissipate: What is an architecture in your opinion?
14:11bbloomdissipate: you're preaching to the choir regarding choice of superior tools in the browser
14:11patchworkAlso, that is what cljs is trying to solve
14:12technomancyhttp://www.buildingkeystones.com/wp-content/uploads/2012/03/no-software.jpg
14:12technomancywhatever that means
14:12dissipatepatchwork, the underpinnings of your software design. the 'stuff' that is not easily changed.
14:12bbloomtechnomancy: lol that's salesforces logo
14:12technomancybbloom: still the deeper meaning is a mystery to me
14:13bbloomtechnomancy: clearly you haven't met the mascots: http://static3.businessinsider.com/image/4e65b08569bedd144500006f-480/salesforce-no-software.jpg
14:13bbloomthat's "chatty" the salesforce chatter mascot in the background there. he's a big red smiley face
14:13bbloom:-)
14:13patchworkdissipate: Since the real world constantly demands change of software, could architecture be a liability then?
14:13dissipatepatchwork, have you seen any of uncle bob's stuff?
14:14dissipatepatchwork, no, not at all. a good architecture let's you swap out technologies like web frameworks, databases etc.
14:14patchworkSo then, the architecture is the backbone that allows other things to change
14:14dissipatepatchwork, correct
14:14dissipatepatchwork, see this on clean architecture: http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html
14:15patchworkUntil your architecture becomes the thing preventing some kind of change : )
14:15patchworkdissipate: I have not heard of uncle bob, I'll check it out. Thanks
14:16dissipatepatchwork, he has a lot of material on clean code and clean architecture. he is also a proponent of Clojure.
14:16winkI haven't read the whole thing, but what I saw of Clean Coder was not so awesome
14:17dissipatewink, not sure about that book, but 'Clean Code' seems to be good
14:17patchworkGot it, so he is preaching separation of concerns
14:17patchworkAny static thing can be made dynamic by adding a new level of indirection : )
14:17patchworkThe Law of Code
14:18winkdissipate: maybe I'm mixing it up, but it was this whole "you have to hone your skills even after going home from your 40+h job" - and I say that as someone who lists programming as a huge hobby
14:18winkdissipate: plus a little know-it-all tone. but as I said, I haven't read both books cover to cover
14:18bhaumantechnomancy: bbloom: they keep using that word, but clearly they do not know ...
14:19patchworkSo the architecture always becomes the base of the tree, it is by definition the thing that cannot change. Or rather, what still has not been granted a level of indirection that allows it to change
14:19dissipatepatchwork, no, it can change, it's just more work
14:20dissipatewink, yeah, i didn't really agree with that part
14:20dissipatewink, professionals in other industries aren't expected to study after work
14:21dissipatewink, but the problem is what do you do if your shop is using bad languages and technologies? in that case, it is in your interest to study outside of work and try to find a better shop
14:21dissipatefor instance, if i worked a java shop, i would work like hell to GTFO of that place
14:23dissipatepatchwork, the 'clean' layered architecture approach has the rule of thumb that you put the stuff that changes more often on the outside layers and the stuff that changes the least often in the inside layers
14:23winkdissipate: yeah of course. but that's intent to grow immensely beyond your current gig. not saying that's a bad thing, but a special case
14:24dissipatepatchwork, do you agree that 99% of software out there is a big ball of mud? especially web stuff...
14:25patchworkdissipate: I haven't seen 99%! I have seen like 0.001 %
14:25patchworkAnd yeah, most of it grew from humble beginnings far beyond its original scope
14:25dissipatepatchwork, extrapolate from a statistical sample. :P
14:25jonasenHere’s a (demo)project of mine I’ve been working on for a while: http://cljsfiddle.net
14:26jonasenIt’s very (very!) alpha still so don’t expect too much :)
14:26patchworkdissipate: knowing how it is going to change beforehand is hard. I have also seen projects set up an architecture they never ended up needing, then growing in another direction and becoming a ball of mud anyway
14:26seangrov`jonasen: This is a great idea!
14:27patchworkTo truly design software well you have to see what you will need in the future
14:27patchworkSince this is impossible in practice, most software is gangly and obtuse
14:27jonasenNote that it'll be quite slow the first time you run a program, after that it will hopefully be a fast edit/run cycle thanks to http caching. Also, I'm only running an in-memory db for now so don't expect your work to be saved for long.
14:27muhooi seee..... lines of code.... requirements changing constantly out from under you....
14:27benkayjonasen++
14:27patchworkmuhoo: You really can see the future!
14:28jonasena more advanced example: http://cljsfiddle.net/fiddle/jonase.bezier
14:28dissipatepatchwork, and why doesn't this happen in other industries like mechanical engineering?
14:28jonasenseangrov`: benkay: thanks
14:28dissipateor electrical engineering for that matter
14:28muhooit does happen in mechanical and electrical engineering
14:28benkayjonasen now implement nrepl.el keybindings
14:28benkayjk jk
14:28dissipateif one's designs were a big ball of mud, they would get thrown out, in those industries, no?
14:28muhooit's slow-motion mud
14:28patchworkdissipate: Because no one comes along and changes the design of the bridge after its built
14:28seangrov`benkay: Yeah, the editor could probably use a touch of work :)
14:29seangrov`Very smart though
14:29seangrov`Well done!
14:29muhoochange is expensive and slow in hardware and mechanical.
14:29benkaydissipate: naw, man. you just hire more grunts to put the stuff together better.
14:29benkaydissipate: or you hire more grunts to test the stuff more rigorously
14:29patchworkThe bridge is there now, people accept it can't change
14:29benkaydissipate: i left for many many reasons
14:29dissipatepatchwork, things change in electrical and mechanical engineering.
14:30dissipatebenkay, from which industry?
14:30patchworkdissipate: Sure, but not after the project is built.
14:30patchworkThe designs change
14:30muhooyes, after it's built. rev 2. rev 3, green wire and dead bugs haging off the board.
14:30jonasenbenkay: heh, that'll have to wait
14:30benkaymultiphysics engineering
14:30benkaydissipate: multiphysics engineering
14:31patchworkmuhoo: Well sure, they change it as much as it can. But bridges are far less adaptable than software
14:31dissipatepatchwork, you aren't disturbed at all by the fact that the average CS grad has no notion of software craftsmanship, or very little? and especially no notion of architecture. they got their degree by banging out code over long nights that none of their TAs can properly review because they went through the same program.
14:31muhooit's just a slower, more expensive process
14:31muhoospeed and cost make people more careful :-)
14:31benkaybig-ish and small-ish systems for http://cascademicrotech.com among others, dissipate
14:31patchworkIf you could modify a bridge as easily as you modify some code, we would see some horrific things
14:31dissipatebenkay, and you left the industry because?
14:31patchworkYou would see software level horror in bridge form
14:32benkayi left the industry for a multitude of reasons, dissipate.
14:32benkayspeed of innovation
14:32benkaycapital requirements for everything
14:32boodleI have a ring app I'm trying to deploy that uses jdbc mysql and sqlserver drivers.. I'm clueless on java and running into this: http://stackoverflow.com/questions/14977228/creating-an-uberjar-for-a-project-that-uses-mysql-and-sqlserver
14:32benkaymean reversion on teams
14:32dissipatebenkay, so you do clojure software development now?
14:33benkayno beer in offices because you can't get insurance if your line operators have access to alcohol on-shift, and providing alcohol to the engineers makes the eng/prod split even worse
14:33loliveira.mt
14:33benkayi do cloud operations. clojure is involved.
14:34dissipatebenkay, i see. seems like out of the frying pan into the fire. but i guess that's just my perspective.
14:35benkaywriting code and managing boxen in service of increasing scale of problems i and my fellas can tackle sanely.
14:35dissipateat least you get to use clojure. so few clojure shops out there.
14:35benkay"mean reversion of teams"
14:35benkayi'm a snob.
14:35seangrov`dissipate: We're (probably) hiring two people who don't know clojure, they're happy to learn it
14:35seangrov`Plenty of places hiring developers
14:35benkayi don't have to design machines in such a way that operators can't rip their fingers off.
14:35benkaythat's a net win.
14:35seangrov`Err, hiring developers to code in clojure
14:36patchworkdnolen: I am enjoying the CSP articles. Thanks for sharing
14:36dissipateseangrov`, you aren't worried how long it is going to take them? i'm coming from imperative languages and this is completely different stuff for me. :P
14:36dnolenpatchwork: np
14:37patchworkdnolen: Have you built any large UI's with this approach?
14:37dissipatebenkay, how long did it take you to make the transition?
14:37patchworkcurious how it scales
14:37seangrov`dissipate: They have good skills and experience. I expect it to be a few weeks before they're up to speed and productive
14:38benkaydissipate: 9 months.
14:38dissipateseangrov`, a few weeks?? wow. someone told me it takes about a year to get comfortable with Haskell. Clojure isn't as bad, so cut that in half to maybe 6 months? a few weeks sounds cray
14:38benkay6 before i was self-sufficient as a consultant
14:39benkay9 total before i was useful in someone else's organizatino
14:39dnolenpatchwork: nope since I'm still learning it, but the autocompleter is a convincing non-trivial example in IMO
14:39dissipatebenkay, wow, that's pretty quick. that's cool
14:39benkaybut that's 9 months of 70+ hr weeks working and studying the computation stack.
14:39dnolenpatchwork: much cleaner than other similar things I've build in the past and more flexible
14:40benkaygranted i wasn't starting from scratch, i had a fair amount of experience in simulation and control system design and implementation.
14:40dissipatebenkay, OpenStack?
14:40benkaydissipate: what about it?
14:40seangrov`dissipate: The ideas are already their in other languages, they're just expressed more succinctly in clojure. Takes time to understand, and I expect they'll be putting in time like benkay, but it's a matter of self-improvement
14:40dissipatebenkay, is that what you are using or are you on AWS or a third party cloud provider?
14:40benkayah.
14:41benkayclient dependent.
14:41benkaythe client that i've been working with the most for the past 5 months is actually a bare-metal shop
14:41benkay>.<
14:41patchworkdnolen: Haven't gotten to the autocompleter yet, I'll check it out.
14:41benkayi wasn't involved in those discussions.
14:41patchworkdnolen: Seems like you would still have to have somewhere to store and access all the channels in a non-gnarly way
14:42dnolenpatchwork: no
14:42dissipateseangrov`, personally, i haven't found anything quite like macros in other languages.
14:42seangrov`dissipate: Meh, reader macros are even crazier :)
14:42dnolenpatchwork: you don't store channels anywhere
14:42dnolenpatchwork: you wire things together but calling functions
14:42benkaybut generally speaking, openstack is overkill for most clients. a simple cloud instance spinup script and provisioning tool serves most totally sufficiently.
14:42justin_smithdnolen: pub-sub :: malloc :: core.async : gc ?
14:42benkaythat said, i'
14:42dnolens/but/by
14:43benkayi'm always looking for larger scales of problem.
14:43justin_smithoops, extra : above
14:43dissipatebenkay, Puppet/Chef?
14:43patchworkdnolen: Ah, you just hook them up? But what if you want to change the wiring?
14:43patchworkinteresting… I'll have to mess with it
14:43benkaychef for big client, salt for smaller clients, been playing around with ansible.
14:43dnolenjustin_smith: pub-sub is one thing you can do w/ core.async, but you want to avoid pub-sub since that's a resource problem
14:43dissipatebenkay, go work for google. that's pretty large scale. :P
14:43benkayf that
14:43dnolenpatchwork: just give the channel to someone else if you need to
14:43benkayorganizational pathology all the way down, dissipate.
14:44benkayplus no actual interaction with business.
14:44dissipatebenkay, but i heard they pay well
14:44benkaylook, we solve problems.
14:44benkaymoney ain't everything.
14:44dnolenjustin_smith: sometimes you do need it of course, I'm still thinking about it, hoping to right up my thoughts on that at some point.
14:44dnolens/right/write
14:44benkaypersonal growth, joy in the experience of life and reputational development are all vastly more important to me and mine.
14:45benkayi'd rather work 30 hours per week for 80k than 40 for 120.
14:46benkay(that said, solving other humans business problems is so fun that i find myself working more than the important humans in my life want me to)
14:47dissipatebenkay, and these business people have no idea you are using clojure?
14:48benkayi strive to find clients who trust me to use the appropriate tools for a given problem.
14:49benkayopen comms are the foundation of trust.
14:49dissipateif they bring other developers on board later, there's going to be some WTFs :D
14:49benkayah, your assumptions are showing.
14:49dissipatehow so?
14:49benkaywell, being 'a developer' tends to cap ones a) influence on projects and b) billable rate
14:50dissipatethat i agree with
14:50benkaywhen i'm 'a developer' on a project, it's typically as a favor to someone and i do the best thing for their project.
14:50benkaywhich, take coinforest.com
14:50benkayjohn and i are friends
14:51benkayi gently suggested he move to AWS
14:51benkayhe said 'lol i r no wat'
14:51dissipateyou are doing bitcoin projects?? interesting...
14:51benkayso i wrapped it up in CM over a couple of nights and stood it up elsewhere. but it's just a wordpress site.
14:51benkayand it works for him.
14:52benkayso now it's in CM and backs itself up nightly.
14:52benkaywithout clojure. 'cause bash is totally sufficient.
14:52futileIs it bad practice to build up a regular expression via raw strings, like (str "(" (join "|" options) ")") ?
14:52benkayeh. if only there were real capital seeking to deploy itself in the bitcoin space.
14:53dissipatebenkay, why did you pick wordpress over drupal?
14:53benkayagain with the assumptions
14:53benkayit's his site
14:53benkayhe stood it up first
14:53benkayi helped him insure it against falling over.
14:54dissipatei don't know about 'real' capital, but i personally made a boatload off my bitcoin investment
14:54benkaywant to fund the development of an options exchange?
14:54benkayit'd only take about 120k by our estimation.
14:55benkaywe'd be doing it in clojure and you could work on it too :)
14:55benkaycame up with a sweet hack to get around the infinite downside problem.
14:55dissipatemaybe... depends on how it is executed.
14:56benkayhow would you want it executed?
14:57dissipatebenkay, one of two ways, either all lawyered up and compliant with the feds, or set up in a way that makes it difficult/costly to shut down
14:57benkaythose are the options, yes ;)
14:58tbaldridgednolen: did we ever fix that timeout bug? I think I'm hitting it in my testing
14:58dnolentbaldridge: sorry we didn't!
14:58dnolentbaldridge: I think those tests are broken, I forget to mention this
14:58devnwhat do people use for debugging in the repl these days?
14:58dnolentbaldridge: let's just comment them out for now and I'll address later
14:58arcatanexecuted with java -jar exchange.jar
14:59tbaldridgednolen: yeah, and in my tests I'm creating a (timeout 500) and it's never closing
14:59dnolentbaldridge: the timeout tests are just badly designed, they shouldn't check for count because that's tied to behavior of dispatcher
15:00dnolentbaldridge: should check that the timeouts-map is purged of particular timeout
15:00dnoleninstead
15:02dnolentbaldridge: if it's actually never closing that's a different problem
15:02dnolentbaldridge: never encountered that before
15:02hyPiRionmy, wrapped booleans are still behaving weirdly
15:02hyPiRion,(and (Boolean. false) true)
15:02clojurebottrue
15:03hiredmanhyPiRion: they always will, clojure doesn't change the wackiness that is Boolean
15:04hyPiRionhm =/
15:05hiredmanclojure canonizes literals, but if you construct random Booleans you are on your own
15:07hyPiRionso the trick is just to know that the primitives false and nil are falsey, and that false? and true? return true if the input is the primitive false/true then
15:12lynaghkbbloom: Reading up on react-
15:12lynaghkbbloom: this stuff reminds me a lot of what I was doing with Singult/C2
15:13lynaghkthough they seem to be doing a lot more optimization on your behalf (rather than complete DOM-subtree walking)
15:13bbloomlynaghk: they basically diff at the sibling level
15:13bbloomlynaghk: which can be problematic for some cross-hierarchy stuff, but in general is pretty rare & easy to work around
15:14bbloomlynaghk: but your render functions don't return full sub trees. they return descriptions of sub trees
15:14bbloom[:button {:id "my-button"} "With some text on it"]
15:14bbloomthat's what you return & the evaluator will later look up the button rendering code & recurse
15:14lynaghkbbloom: right.
15:14bbloomit's a good design
15:15lynaghkconceptually it's similar to function composition in hiccup, no?
15:15bbloomyes
15:15bbloomie functional :-)
15:16bbloomif the render finds that you give it a description of an object that already exists (ie has the same hierarchy path, element type, and optionally a string-key for matching up moving elements in a list view or something like that) then it will preserve the state & transfer over any new parameterization
15:16lynaghkbbloom: yeah, I liked writing UIs in that style with C2 and singult---the only issue was perf.
15:16bbloomotherwise, it will throw away the state of that widget & detatch handlers & all that
15:16bbloomlynaghk: sure, perf sucks if you do the naive implementation
15:16bbloomand i mean naive as in the technical sense, not as in you're stupid :-)
15:16lynaghkbbloom: of walking the subtree on each call to render
15:16bbloomwhat react does is aggressive memoization
15:16lynaghk(In singult it's called "merge")
15:17bbloomyou can stop walking a subtree if you ever discover the parameters are not different
15:17bbloomand if you only ever walk data & never touch the dom, it's much faster
15:17lynaghkbbloom: https://github.com/lynaghk/singult/issues/3
15:17bbloomreact fully virtualizes the dom. it never looks in the real dom for anything unless it HAS TO for a browser quirk or whatever
15:17bbloomlynaghk: ok so then yeah, you get this :-)
15:17bbloomyou should like this then! :-P
15:17lynaghkbbloom: = )
15:18lynaghkbbloom: I love having ideas and then finding out smarter people implemented them better.
15:18bbloomhaha
15:19bbloomyeah, your thing sounds just like react
15:19bbloomwhere you screwed up was exposing the render function :-)
15:19bbloomie the one returning a live dom node
15:20lynaghkbbloom: I dunno about this JSX preprocessor stuff though; conceptually it seems like we're all on the same page---the real question now is the tradeoffs of html-ish syntax vs a richer format like hiccup or this react data stuff where you can have explicit references to shit besides strings
15:20lynaghkbbloom: you mean react sounds just like my thing from 12 months ago =P
15:20bbloomlol whatever
15:21bbloomi'm not a big fan of the JSX idea in general b/c i hate xml notation & such an extension procludes use of other syntax extensions… you know… like coffeescript :-)
15:21lynaghkbbloom: The one place where this doesn't work out super great is when you want to compose with other libs that don't know about this style
15:21bbloombut in clojure w/ hiccup-style notation, it's basically the same idea
15:21lynaghkbbloom: e.g., for a client project I had to add this "ignore" special type to singult so that in a subtree I could throw a jQuery drag and drop thing
15:21bbloomlynaghk: react's escape hatch for that is here: http://facebook.github.io/react/docs/working-with-the-browser.html
15:22lynaghkyeah, damn. this react thing is very similar to Singult.
15:22lynaghk"in memory representation of the DOM" <=> hiccup.
15:22bbloomlynaghk: cool now explain it to dnolen :-)
15:22lynaghkthough in their case you can have special tags
15:23bbloomyeah, the special tags is critical. it's your abstraction mechanism
15:23coventryI find the Ritz debugger a bit awkward to use. It's slow to start up, and the need for break-on-exception to use breakpoints means you break on lots of irrelevant exceptions. Would there be any value to an in-clojure debugger which works like edebug? That is, a special reader which instruments forms with debugging calls as it evals them?
15:23bbloomcustom tags == functions, not objects
15:23lynaghkwheras in hiccup if you do something like [:ol (my-special-list-item-template data)] then you lose the semantic info
15:23bbloomSTATEFUL custom tags == functions w/ loops in them that break out of the loop when the parent function stops including that ID in the dom
15:23lynaghkcompared to [:ol [:my-list-element {:data data}]]
15:24bbloomlynaghk: yeah, that's something i'm trying to solve. unfortunately i think there are only two solutions: 1) explicitly defer execution by using vectors & keywords (my current solution)
15:24bbloomlynaghk: and 2) totally custom language/evaluator
15:24bbloomreact is basically doing #1 with a sprinkling of #2 for using xml notation instead of vectors & keywords
15:25futileDoes Clojure or Java have an analog to Core Data for local programs?
15:25dnolenbbloom: lynaghk: I dunno about this tree walking stuff
15:26dnolenbbloom: lynaghk: why not compile templates ahead time + core.match
15:26bbloomdnolen: what does core.match have to do with anything?
15:26futileMaybe core.logic or Datomic makes sense for this.
15:26dnolenbbloom: why do you need tree walking?
15:27lynaghkdnolen: in Singult the tree walking was naive and done on fully-rendered DOM elements. There are situations where this is useless (e.g., if you want to change the type of an element at a given position---the walker has no idea what it's supposed to do).
15:27dnolenbbloom: throw that out the window think about precompiled templates + matching
15:27dnolenbbloom: convert the data into paths, push through a template that uses pattern matching
15:27bbloomdnolen: you only need tree walking when your backend renderer is a tree. in my prototype, i use this model & there are two possible backends: one that returns a dom-like tree & one that returns a list of java2d/canvas-style draw commands
15:28bbloomdnolen: the dom backend walks a tree, but the tree is an implementation detail for updating the dom via a diff
15:28bbloomdnolen: the java2d backend just does full re-rendering & that's fast enough for small apps. in larger apps, it will need to memoize layers in to textures
15:29bbloomi don't see how precompiled templates help, since you're building dynamic UIs. the template will need just as much branching & looping as your render functions that return javascript data structures instead of html snippets
15:31mimieuxduck1123: Does exist a ciste tutorial?
15:31duck1123mimieux Not really. I've been meaning to write one for the longest time, but never have
15:32lynaghkbbloom: in this scheme, how do you imagine event handlers working?
15:32lynaghkbbloom: that your custom components handle the low-level events, and they have some way of emitting them back upstream as application-semantic events?
15:33bbloomlynaghk: i'm planning on using a multi-pass model
15:34bbloomlynaghk: even though there are two backends for *rendering* (dom + canvas) there are other backends for other use cases too
15:34bbloomlynaghk: for example, event processing or hit testing
15:34bbloomlynaghk: you can think of the code you write as being a traversal over a data structure & then you parameterize your traversal with different evaluators
15:34bbloomhave you ever done any 3d/game/graphics programming?
15:35lynaghkbbloom: not a ton outside the web
15:35bbloomever heard of a shaddow map?
15:35lynaghkbbloom: actually, lets step back from events real quick---I'm trying to explain to my designer what this approach would look like compared to frankenstein string attributes in HTML for templating.
15:36lynaghksince if he wants to control the markup/CSS, he'll need to use something closer to hiccup than to slim.
15:37lynaghk(hiccup having clojure's richer data structures to play with, compared to stringifying everything in HTML for a runtime evaluator based on the HTML)
15:37bbloomwell, ignoring event handling, it would look a lot like react: you just write a pure render function that looks at some args, does normal code branch/loop code & then returns some dom-like node thinggies
15:38mimieuxduck1123: ok, now reading jiksnu.
15:38lynaghkbbloom: my question is what the dom-like thing looks like--does it have higher-level semantic info in special tags/attributes?
15:38bbloomit's just data, make it look however you like
15:38duck1123mimieux, if you have any questions, let me know. I love getting feedback
15:38lynaghkbbloom: like, you have a [:unify {:data data :mapping-fn ...}] tag instead of a fully rendered [:container element1 element2 ...]
15:39mimieuxduck1123: sure!
15:39lynaghki.e., you pass the unevaluated fn as a tag to the renderer so that it can more intelligently handle the dom
15:39bbloomlynaghk: you could create a thunk, but you're probably better off returning some data structure w/ a name & some arguments
15:40lynaghkbbloom: right, that's my question
15:40bbloom[:widgets/tab-controls {:tabs […]}]
15:40bbloomor something like that
15:40bbloomif the renderer sees divs & spans & shit, it draws them or updates the dom. otherwise, it expands the widget
15:41lynaghkright
15:41lynaghkbbloom: how are you controlling scope?
15:41bbloomok so on to the event handling idea :-)
15:41bbloomscope of what?
15:41bbloomeverything is lexical
15:41bbloomexcept the tag names
15:42lynaghkyou don't want everything to have access to the toplevel scope, otherwise if anything changes up there you have to re-render everything
15:42bbloomyeah, you have to thread data down the views as arguments
15:42lynaghkyou want the minimum scope per subtree---an explicit list of what data that subtree depends on, so that you can memoize effectively
15:42lynaghkbbloom: okay, right.
15:43bbloomyeah, look at how react does that: it divides data in to two halfs: 1) props 2) state
15:43lynaghkbbloom: so is it that each tag is basically a fn call
15:43bbloomyeah, just deferred until the renderer decides if it needs to call
15:43bbloomthere is a 3rd pseudo set of data, which are the children, so you can write <Tabs><Tab>asdfasdf</Tab></Tabs>
15:43lynaghkthe children are opaque to the parent?
15:43bbloombut that's just sugar for a "children" key in prop
15:43bblooms
15:44bbloomyou have to explicitly render your children
15:44lynaghkbbloom: can we schedule a time to pair-program a whitepaper example of what todoMVC looks like with this approach?
15:45bbloomlynaghk: here's my non-functioning example that is surely bugged:
15:45bbloomhttps://gist.github.com/brandonbloom/0acd45c60860e4dd562f
15:46bbloomlynaghk: that's an approximate goal for my code. i have something about 5x as verbose as that working & i'm adding the features i need to get it to work properly. i'm focusing on the java2d backend for now tho, since i know that this approach works in react & i want to prove it's more general
15:46bbloomwhoops copy paste fail
15:46bbloomrefresh
15:48lynaghkbbloom: are you using keywords as a shortcut for clasess?
15:48lynaghk(section :main ...)
15:48lynaghkbbloom: you've seen my singult todomvc, yeah? https://github.com/lynaghk/todoFRP/blob/master/todo/c2/src/cljs/todo/list.cljs
15:49lynaghkwell, c2+singult.
15:49lynaghk(same thing; c2 uses singult under the hood)
15:49bbloomlynaghk: maybe a long time ago? :-)
15:49lynaghkbbloom: are these actually fn applications per tag? It seems like you should have a separate evaluator, not Clojure's
15:50bbloomlynaghk: yes, i need a separate evaluator
15:50bblooms/defn/defview/
15:50lynaghkokay.
15:50bbloomthe definition of a view is basically `[~fn-name ~@args]
15:50bbloomheh
15:50lynaghkI think namespaced keywords as tag names would work fine
15:50lynaghkyeah.
15:50bbloomyup
15:50bbloomnow, two interesting things:
15:51bbloom1) i mixed event handling directly in there
15:51bbloomwhich can be a bit ugly, but i haven't designed yet a more general aspect-oriented system for injecting concerns like that
15:51lynaghkaspect-oriented?
15:52bbloomyeah, so like if i want to have some bit of behavior that runs before the behavior of every button, i should be able to (defaspect :before ::widgets/button ...)
15:52bbloomor something like that
15:52bbloomwhich would let me separate arbitrary logic, rather than just separating event handling from rendering
15:52bbloomi think for simple cases & non-abstract components, strict separation of concerns is a waste of time
15:52bbloomsometimes, you really do have a ONE OFF component. hell, MOST of the time
15:53bbloomin that case, it's fine to couple things & just do whatever works. you can always refactor & abstract/parameterize later
15:54lynaghkbbloom: I wonder if you could implement that using CSS-style selectors on the vDOM
15:54lynaghkvDOM = virtual DOM (or whatever you want to call the pile of vectors)
15:55bbloomlynaghk: yeah, that's the idea, but CSS has a lot of DOM-warts & it's both too flexible & not flexible enough for my needs. so i punted on that & just did the concrete, non-separated thing for now
15:55bbloom1 step at a time :-)
15:55bbloomnow you wanna hear how events work? :-)
15:55lynaghkyes.
15:55lynaghk= )
15:55bbloomhttp://www.cs.unc.edu/~zhangh/technotes/shadow/onebigfig.jpg
15:55bbloomok so that's an example of how shadow mapping works in a 3d game
15:56bbloomnotice that the final image is produced by composing a texture from the camera's view & a texture from the light's view
15:56bbloomthere are two "renderers": the color view & the depth view
15:57bbloomand there are two "observers" the camera & the light
15:57bbloomconceptually, you evaluate the scene from both observer's views & with both renderers
15:57bbloomin reality, you don't need the light's color view, only it's depth (notice no arrow from it) that's just there for illustration
15:57bbloomyou have some data set which represents all the things in your scene
15:58bbloomand you have a "query" on that database
15:58bbloom"give me all the things in the view frustum"
15:58bbloomand you pass the results of that query to the renderer along with the observer as a parameter
15:59bbloomsimilarly, i might query that database & say "give me all the things that intersect this line" or "give me all the flowers" or whatever
15:59bbloomyou can conceive of many queries
15:59bbloomand many ways to process those queries
15:59bbloomso one way to think of UI rendering is to think of it like a query on your view data structure "give me all my view objects"
16:00bbloomyou can encode that strictly as data or you can write an explicit traversal
16:00bbloomand if you swap in a different "renderer" which is, more generally, a different "evaluator" then you can perform different tasks
16:00bbloomso each traversal pass, i parameterize with a different evaluator: one for rendering & another one for event processing!
16:01bbloomso when rendering, (clicked? :whatever) => false
16:01bbloombut when event processing, it might return true
16:02bbloommake sense?
16:03bbloomideas shamelessly stollen from here: http://mollyrocket.com/forums/viewforum.php?f=10
16:03lynaghkhmm
16:05bbloomhopefully i explained that clearly, it's kinda a heady idea
16:06bbloombut notice how nice the resulting code looks :-) it's super terse & to the point
16:06bbloomit will be *slow as hell* to start, but it's actually really straightforward to optimize b/c you can memoize/cache at pretty much any level
16:08bbloomlike for games, imagine nothing in the view of the spot light ever moves. you don't need to re-render the texture!
16:08bbloom:-)
16:13lynaghkSo in general the scenegraph for view rendering can be completely different than the event scenegraph
16:13lynaghk?
16:20dnolenbbloom: yeah not yet convinced about traversal stuff, nor diff'ing stuff, nor how templates are traditionally handled - I've got some ideas I'm poking around with
16:20bbloomdnolen: looking forward to seeing your approach :-)
16:21dnolentbaldridge: were you able to sort out the bug?
16:21tbaldridgeyeah, it was a bug in close!
16:21dnolentbaldridge: cool will give it a spin then
16:22tbaldridgednolen: something breaks for me with advanced compilation, it's like MessageChannel is super slow in adv more. Perhaps if you hit that bug you can help me figure it out.
16:23dnolentbaldridge: seems strange will poke around
16:25zeitueis there anything like codecademy for clojure?
16:28callenzeitue: that's a really good idea.
16:28callenzeitue: 4clojure is pretty close.
16:28zeituecallen: that's what I was looking for cause I'm teaching a few the language
16:29dnolentbaldridge: what are you running that looks slow?
16:29tbaldridgednolen: https://gist.github.com/halgari/6323472
16:29zeituethanks for the recommendation I've seen that though now sure on it callen:
16:30dnolentbaldridge: is that what you added to the tests, I see you're timing something now?
16:30tbaldridgednolen: In chrome that takes 3000ms to run in simple, with adv it takes ~1000ms to run, the first time, if I reload the page it takes 70000ms, and continues to be that slow until close the tab and load it up in a different tab
16:32tbaldridgednolen: yeah, I need to remove that from the tests, but yes, it's timing total time to put/take 1mil items from a (chan)
16:32dnolentbaldridge: ok will try running tests in advanced
16:35dnolentbaldridge: I can't reproduce your problem, neither in Chrome nor Chrome Canary
16:35dnolentbaldridge: I can't believe that runs so quickly!
16:35tbaldridgednolen: okay, I'm fine with that perhaps we're good then
16:39dnolentbaldridge: Huzzah!
16:39tbaldridgednolen: it's faster for you?
16:39dnolentbaldridge: Node.js Go daisy chain benchmarks takes 732ms!
16:40tbaldridgednolen: down from?
16:40dnolentbaldridge: setImmediate alone by itself takes ~350ms
16:40dnolentbaldridge: 100000 calls to setImmediate, so we're adding just a little bit of overhead to that.
16:41tbaldridgednolen: yeah, a ring benchmark is like the worst case for the new dispatcher. Assuming only one message is being passed around the ring.
16:43callentbaldridge: is this supposed to be like the thread ring benchmark on the shootout?
16:43dnolentbaldridge: it's about ~250ms improvement over old perf
16:43tbaldridgednolen: eh, not too bad then.
16:46tbaldridgecallen: yeah, a ring benchmark is like a recursive fibonacci benchmark, all you're doing is benchmarking overhead that wouldn't be a problem in real life code.
16:47dnolentbaldridge: there are still some boolean things but if you merge master I can patch that stuff up
16:47tbaldridgednolen: kk, if you're not seeing any bugs then I'll merge.
16:48dnolentbaldridge: lemme test my autocompleter real quick
16:49dnolentbaldridge: works like a charm, go for it
16:50tbaldridgedone
16:50tbaldridgeand hey! 200 commits to core.async!
16:51callentbaldridge: I know that. I was just asking if it was comparable to thread ring or not.
16:51tbaldridgecallen: I'd imagine so, I haven't seen the code dnolen was running
16:52callentbaldridge: do you guys squash commits for clean bisect in core.async?
16:52callen(asking because of the 200 commits #, which sounds low to me)
16:52dnolencallen: it's basically a thread ring yes
16:52dnolencallen: 100000 channels linked together, benchmarking put something in at one end reading it at the other.
16:52tbaldridgecallen: no I haven't seen that done with this project
16:52callendnolen: very cool. I've been using the ability to write things like core.async as a library, as a way to demonstrate the value of Clojure at work :)
16:53callentbaldridge: sounds like very few commits for a project of that scope. *takes a look*
16:54tbaldridgecallen: actually, I developed the go macro over a week in a different repo, so that does skew things a bit.
16:55callentbaldridge: it's not totally clear to me who's responsible for what parts of core.async.
16:57avishaianybody here using appengine-magic?
16:57tbaldridgecallen: Rich did the channels, and I wrote the IOC stuff, the rest of it was collaboration between Relevance people, Rich and dnolen.
17:00callentbaldridge: thanks. Is there a good primer on getting into the headspace behind how it works somewhere?
17:01srrubyI'm a Rubyist/former Java programmer looking for Clojure work. Any tips ? I'm glad that Lisp is getting more popular!
17:01callensrruby: contracting with clients that trust you to do what makes sense.
17:01callensrruby: if you're in the bay area, there are companies that use Clojure.
17:02srrubycallen: Thanks, and yes I'm in the bay area. I'm starting to send out resumes locally.
17:02callensrruby: you really should be working on stuff of your own accord though.
17:03callenIt's not really fair or reasonable to expect an employer to pay you to learn Clojure on the job.
17:03gtraksrruby: Joy of Clojure is worth the time/effort investment.
17:03tbaldridgecallen: not that I'm aware of, the best thing I can point out to you now is to read both channels.cljs and async.cljs. Today I rewrote this CLJS code so it's a bit easier to understand. The thing is, you can cancel callbacks, so every callback has to have commit executed against, and that makes things a bit harder to understand.
17:04srrubycallen: I am and getting pretty good at it. I'm porting one of my open source projects from Javascript to Clojure.
17:04tbaldridgecallen: once you grasp that, think "now how would I do this with multiple threads", and then read channels.clj.
17:04tbaldridgecallen: rich spent a ton of time figuring out all the lock stuff on the JVM, and that's something I hope I never have to do.
17:04callentbaldridge: I understand systems like core.async conceptually, it's the state machine rewriting that is more puzzling to me.
17:04tbaldridgeah
17:04callenoh, the lock stuff would be interesting too I suppose.
17:05callensrruby: if you need something to hack on in Clojure, I've always got a long list of things on my open source to-do list.
17:05tbaldridgecallen: have you seen this? http://hueypetersen.com/posts/2013/08/02/the-state-machines-of-core-async/
17:05callenI have now, thanks.
17:06tbaldridgecallen: that goes through the output of the macro. For the actual guts I always suggest that people read this: http://en.wikipedia.org/wiki/Static_single_assignment_form and then just view the go macro as a micro compiler.
17:06tbaldridgecallen: I hope that helps a bit
17:07srrubycallen: Could I see the list?
17:07callentbaldridge: I knew SSA was involved. this should help tie everything together, thank you very much :)
17:10callensrruby: https://www.refheap.com/17988
17:10callen`cbp: wakie wakie, eggs-n-bakie.
17:11duck1123That's quite a list for someone learning clojure
17:12callen`cbp: this is the current to-do list: https://www.refheap.com/17988 are you still working on sync! for Pomegranate?
17:12callenduck1123: he asked for my to-do list, not for a learner's primer.
17:12callenduck1123: half the stuff on there is pretty doable for a new person anyway.
17:12srrubycallen: Looks pretty daunting. I better finish my project first :)
17:13callenthe only really tricky one might be proxy+
17:13callenthat might be horrific if not impossible. I don't really know. Depends on how usable the Annotation(Visitor/Writer).java stuff is.
17:20`cbpcallen: hihi
17:20`cbpcallen: technically no because i've been extremely busy but I was hoping to do more this weekend
17:20callen`cbp: sounds awesome. Thanks :)
17:23dnolentbaldridge: wow, thread ring in Chrome takes 200ms, same as Clojure
17:23tbaldridgenice!
17:23callendnolen: n of what?
17:23callen100k or 1mm?
17:24dnolenhttp://gist.github.com/swannodette/6323988
17:24dnolencallen: 100k
17:24dnolentbaldridge: that is pretty amazing
17:25tbaldridgednolen: I was hoping we could get to this point. There was a ton of crap in the channels that was multithread specific.
17:27dnolentbaldridge: a lot of fun stuff I want to try now :)
17:31bbloomcool stuff guys!
17:35shaungilchristwell that was odd, not sure why but ioc_helpers.run_state_machine_wrapped stopped being added to compiled cljs. lein cljsbuild clean fixed it but it would be nice to know why
17:36callenshaungilchrist: I assume by default that anything involving cljsbuild (however very nice it is) involves vague gesturing and magic incantations :P
17:37dnolenshaungilchrist: probably stale stuff in your target directory, often happens if you pull in a new version of some lib
17:40tbaldridgeI always do cljsbuild clean after an upgrade
17:40callentbaldridge: that pattern/habit probably merits documenting.
17:40tbaldridgedocs? what is this, ruby?
17:40shaungilchristhahaha
17:41callenI'm documenting the cargo cult right now. Somebody else can confirm/repro.
17:41shaungilchristthe upside of it was walking through the core.async source and compiled output which was (seriously) a thing of beauty
17:42callenhttps://github.com/emezeske/lein-cljsbuild/pull/223
17:42callentbaldridge: I'm in Klishin's camp. Documentation uber alles.
17:43tbaldridgewell yes I was being sarcastic
17:43callenI'm perpetually serious.
17:45dnolentbaldridge: wow flame graph profiles, memory profiles for core.async are GORGEOUS now in chrome
17:45bbloomdnolen: screen cap? :-)
17:45bbloommaybe even a before/after? :-P
17:46dnolenbbloom: haha, I'll put something together but my push 1 millions items in a range into a channel + read them out use to involve a incredible long tail before GC kicked
17:46dnolennow it's like goddamn CLIFF
17:46dnolenBOOM memory reclaimed
18:03dnolentbaldridge: you're queuing dispatcher is sweet :), I believe it's the reason we're seeing such good GC behavior
18:03tbaldridgeI wonder why that is. I wouldn't have though it would have a impact on memory.
18:04tbaldridgednolen: BTW, we probably want to update the ring buffer at some point to set old slots to nil after they are popped, that should help the GC in some cases as well.
18:04tbaldridgednolen: unless you know of a reason why we shouldn't
18:05dnolentbaldridge: no that sounds like a good idea to me
18:08dnolentbaldridge: I'm pretty it's because we don't pound the browser with dispatches now esp in the case of (chan), they aren't cheap
18:09tbaldridgeah yeah, I could see that
18:09dnolentbaldridge: it used to take 16 seconds to do 1000000 events with (chan) in Chrome
18:09dnolentbaldridge: now 1.5seconds
18:09tbaldridge:-D
18:09callengood lord. what'd you change to create such an improvement?
18:09shaungilchristwow that is awesome
18:10tbaldridgecallen: rewrote channel from scratch, switched from arrays to a ring buffers, implemented a custom event queue. and a ton of CLJS magic
18:10callenvery cool. :)
18:11callentbaldridge: I take it you've read about LMAX Disruptor?
18:11futilednolen: whoa.
18:11dnolentbaldridge: definitely blown away that (chan) is this efficient now
18:11tbaldridgecallen: yeah, sadly it doesn't work at all for the JVM stuff, but we're using something like that in CLJS now. Of course there's only one thread in CLJS so it's basically a ring buffer at that point.
18:12callenThat makes sense.
18:12bbloomi'm available any time you need me to just say the name of a data structure & then sit back & let you guys do all the work :-)
18:13bbloomreally, good stuff guys. thanks for being awesome w/ that stuff
18:37clj_newb_2345anyone know of a good resource for "Clojure Pedestal" for people whose IQs aren't 4 digits?
18:39nDuffclj_newb_2345: have you walked through the tutorial?
18:39nDuffclj_newb_2345: it's several hours, but it's hours well-spent.
18:39callenclj_newb_2345: are you working on a complicated web application?
18:39callenclj_newb_2345: or are you just trying to learn to do web dev in Clojure?
18:42arkhclj_newb_2345: in addition to the pedestal app-tutorial, samples and pedestal.io documentation (not in that order) I'd recommend https://github.com/taylorSando/pedestal-todo/blob/master/beginners.md
18:43callenclj_newb_2345: if you're just learning how to do web dev in general with Clojure, Pedestal isn't a very good fit. It's better for more experienced Clojure users making web apps that are complicated in a particular way.
18:44ucbcallen: I'm sure you've seen https://github.com/drcode/webfui before. What do you think of it?
18:44ucbalso hi!
18:46callenucb: yeah I've seen webfui before. no opinions. Seems like a plausible way to do things.
18:46callenucb: hi! how are you?
18:46callenI've mostly been learning more Datomic lately.
18:46ucbcallen: good stuff, thanks. I'm well, how you?
18:47callenVery good, looking forward to testing Clojure/Datomic at work for a project.
18:47ucbnice
18:47callenDidn't take long at all to find an excuse. :)
18:47ucbdatomic on the browser mayhaps?
18:47callenit does map nicely to the problem.
18:47callenucb: nah, this is backend stuff.
18:47ucbhammers and nails
18:47callenneed to aggregate data from a bunch of different sources and have a traversable history of the universe.
18:47callenideally with efficient aggregations and relationships.
18:47callenwhich datomic fits neatly.
18:48ucbnice
18:49ucband having said that, zzz
18:53agumonkeyhey clojurists
18:53agumonkeyI just wrote a weird take-like function
18:54agumonkeytaking overlapping frames of a list
18:54agumonkey(frame (range 6) 3)
18:54agumonkey((0 1 2) (1 2 3) (2 3 4) (3 4 5))
18:54agumonkeyis there a common name for this function ? I'm sure it exists already
18:55hyPiRionagumonkey: partition
18:55agumonkeypartition do overlaps ?
18:55hyPiRion,(partition (range 6) 3 1)
18:55clojurebot#<IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Long>
18:55hyPiRionbr, wrong way
18:55ChongLi,(partition 3 1 (range 6))
18:55clojurebot((0 1 2) (1 2 3) (2 3 4) (3 4 5))
18:55hyPiRion^
18:55agumonkeyI'll be damned
18:55agumonkeythanks a ton of lots
18:55tbaldridgeagumonkey: careful....
18:55agumonkeywith the partitioning or the daming ?
18:55tbaldridge, (partition 3 1 (range 7))
18:55clojurebot((0 1 2) (1 2 3) (2 3 4) (3 4 5) (4 5 6))
18:56tbaldridgepartition drops partial segments
18:56tbaldridge, (partition-all 3 1 (range 7))
18:56clojurebot((0 1 2) (1 2 3) (2 3 4) (3 4 5) (4 5 6) ...)
18:56tbaldridgebleh, I'm failing here
18:56tbaldridge, (partition 2 (range 3))
18:56clojurebot((0 1))
18:56agumonkeyalright, that's what my unnecessary `frame` was doing anyway
18:56tbaldridge, (partition-all 2 (range 3))
18:56clojurebot((0 1) (2))
18:57tbaldridgejust be aware of the difference, I've lost some time on that oddity
18:57hyPiRionwhat tbaldridge means is that the last two partitions are removed (the (5 6) and (6)) when using partition
18:57agumonkeyAnd I actually remember reading these partition* functions in dash.el emacs lib ... I can't even reuse prior lisp knowledge
18:57hyPiRionthey are kept with partition-all
18:57tbaldridgehyPiRion: yeah, what he said
18:57rasmustoor with #(partition % 1 someseq)
18:58rasmustothat I happen to use a lot
18:59magnarsagumonkey: partition and partition-all work the same in dash as in clojure - just that there is no optional step argument. There's a separate partition-in-steps and partition-all-in-steps instead.
19:04agumonkeymagnars: hey, well then I don't know where I got this idea
19:05agumonkeymagnars: is there a lot of clojure in dash ? or is it more mainstream/vintage lisp ideas ?
19:05magnarsit borrows heavily from clojure
19:05agumonkeyok
19:15clj_newb_2345nDuff, callen: arkh: I've already played with ClojureScript / ring / moustache / enlive
19:15clj_newb_2345this is basically "Pedestal, nothign else will do"
19:15clj_newb_2345I like their model of updates
19:15clj_newb_2345and how it updates the DOM
19:16callenclj_newb_2345: there is a Pedestal channel on FreeNode, might be a better resource than this one.
19:19seangrov`After tinkering for awhile, I'm ready to ask for help
19:20seangrov`I'm making a toy battleship implementation in cljs, and I would like to have multiple implementation of the board - a single array, and array of arrays, maybe something else
19:20seangrov`Is this a use case for defprotocol and deftype?
19:20callenseangrov`: single array being partitioned according to row/col?
19:20seangrov`callen: Yeah, by calculating the offset
19:21callenseangrov`: the protocol is the API for interacting with the boards, the deftypes are the boards themselves, no?
19:21seangrov`Whereas the second implementation would be [[row-1][row2]...]
19:21seangrov`Yeah
19:21seangrov`Trying to make sure my understanding isn't too far off here
19:25`cbpseangrov`: maybe a multimethod and your dispatch fn can tell what kind of board it is based on the structure?
19:27llasramNote to self: do not write macro-writing macros
19:28llasramI've apparently had a library with `(~~fname ...) for years where I really needed `(~'~fname ...)
19:28`cbpseangrov`: I would probably model it as a set of occupied coordinates + possibly a set of checked coordinates though.
19:29seangrov``cbp: Yeah, I have one implementation that works just fine, but I would like to separate it form the e.g. rendering code that's going to be consuming it and the game logic that'll be interacting with it
19:38eric_normandanyone using liberator 0.9.0?
19:38eric_normandI have a question about responses.
19:54clj_newb_2345callen: ha, nice, thanks!
19:55seangrov`It seems like protocols lend themselves towards mutable state
19:55seangrov`I'm probably using them incorrectly though
19:56bbloomseangrov`: why do you feel that they lead you that way?
19:58seangrov`bbloom: I'll post the code in a bit and ask for some review, it's pretty small
20:04callenllasram: nice.
20:11clj_newb_2345is there any wrappers of the _git api_ as a clojure library?
20:11clj_newb_2345actually, wait
20:11clj_newb_2345if I want a database with git like "DAG" structure
20:11clj_newb_2345if I want adatbase with "DAG" like forking / remembering of history, is Datomic what I want?
20:13bbloomclj_newb_2345: not really. Datomic is more like git with only a master branch, plus a fast query engine
20:13bblooma multi-master version of datomic w/ a different set of trade offs would be awesome for a different set of use cases, though
20:14clj_newb_2345bbloom: so "datomic", roughly, is "CVS + fast query engine"
20:14clj_newb_2345or rather, it's a "line" with a fast query engine, not a DAG
20:14bbloomclj_newb_2345: well no b/c CVS stores diffs
20:15bbloomclj_newb_2345: datomic works like git, but the only shared branch is master. you can have local, uncommitted branches
20:15clj_newb_2345doesn't datomic store diffs? how else does it story the history?
20:15bbloomgit doesn't store diffs
20:15bbloomhow else does it store history? :-)
20:15hiredman(which is amazing, btw)
20:16clj_newb_2345how does git store history?
20:16bbloomclj_newb_2345: http://vimeo.com/14629850
20:16clj_newb_2345oh, git blobs
20:16clj_newb_2345that's what the hashes are for, no?
20:16bbloomthe hashes are version numbers b/c you can have multiple committed masters in a distributed manner
20:17bbloomdatomic just uses an incrementing number for the basis time (ie version number)
20:18clj_newb_2345first world problem: the video is too big to play nicely n my nexus 7
20:20hiredmanI wonder if datomic does a cas like thing
20:21bbloomhiredman: my understanding is that it's strictly serialized
20:21bbloomhiredman: the server may be multithreaded, but transactions go in to a queue & a single consumer processes them linearly
20:21bbloomno need for cas then
20:21hiredmanbbloom: ah, I mean content addressable storage, wrong cas
20:22bbloomoh haha
20:22bbloomhm, yeah, i imagine it must right?
20:22bbloomit stores large chunks of indexes in block storage
20:22hiredmanI dunno
20:22bbloomwhat else would it call the blocks?
20:23hiredmanactually I guess it must
20:23bbloomi mean it *could* name regions of the indexes & store those names
20:23bbloombut seems like a waste
20:23hiredmandunno, makes sense, I was going to say "oh, I assume a cas would have to be based on hashing" and then thought "oh, right"
20:24bbloomhiredman: i bet you can find out quite easily if you set up a store & peek in it
20:24bbloommaybe somebody here has a store set up that they can run a sub-datomic level query & see what keys they got in there:-)
20:24hiredmanmeh, seems like a lot of work
20:25clj_newb_2345besides datomic and fleetdb; are there any other databses implemented _in_ clojure?
20:25clj_newb_2345i'm more curious in how implementations work rather than raw performance
20:36callenclj_newb_2345: https://github.com/ninjudd/jiraph sorta.
20:36callensame pluggable backend type design as Datomic.
20:58bbloomdnolen: hey perf man. question for you
20:58dnolenbbloom: what's up?
20:58bbloomdnolen: any reason vector nodes don't have cached hash values? seems odd that (hash (conj v :x)) is always going to be linear
20:59dnolenbbloom: huh, no particular reason no - I'm surprised we don't cache the value.
20:59muhoo~cas
20:59clojurebotExcuse me?
20:59dnolenbbloom: I'm also up for the incremental hash calculation that people have brought up
20:59muhoowhat is cas?
20:59callenmuhoo: compare and swap
20:59muhoothx
20:59bbloomcallen: except not above
20:59muhoo~cas is compare and swap
20:59clojurebot'Sea, mhuise.
21:00bbloommuhoo: it also means "content addressable storage"
21:00bbloomwhich is what hiredman was talking about
21:00muhoo~cas s compare and swap or content addressable storage
21:00clojurebotHuh?
21:00muhoo~cas is compare and swap or content addressable storage
21:00clojurebotIn Ordnung
21:00muhoo~cas
21:00clojurebotcas is compare and swap or content addressable storage
21:00callennice.
21:00muhoo(inc clojurebot)
21:00lazybot⇒ 30
21:00callen(inc muhoo)
21:00lazybot⇒ 1
21:00bbloomdnolen: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/APersistentVector.java#L140-L145
21:00callenasking questions is goooooood
21:00bbloom:-( sad
21:00muhoo~frp
21:00clojurebotIt's greek to me.
21:01callenmuhoo: functional reactive programming
21:01muhoo~frp is functional reactive programming, or fiberglass reinforced plastic
21:01clojurebotAlles klar
21:01dnolenbbloom: oh, you're asking about CLJ, yeah this would be nice enhancement no? :)
21:01bbloomdnolen: it's also true of cljs
21:01callen~frp
21:01clojurebotfrp is functional reactive programming, or fiberglass reinforced plastic
21:01bbloomdnolen: i checked both
21:01muhoo~java logging
21:01clojurebotjava logging is clown shoes
21:01muhoo:-)
21:01callenPerfekt.
21:01dnolenbbloom: ok you're asking about incremental hashing
21:01muhoook back to work for me
21:02callenI love it when people break servers dev environments depend on.
21:02dnolenbbloom: yes this is a good idea, up for a patch to CLJS
21:03bbloomdnolen: ok :-)
21:03dnolenbbloom: Mark Engelberg brought this up with respect to CLJ, probably just need to submit a patch and bug one of the core devs
21:08bbloomdnolen: ok thx. i dunno if i'll bother to patch it, but good to know i'm not crazy for wanting that
21:09dnolenbbloom: if you feel so inclined feel to free to open a ticket for it. Michal might take it.
21:09bbloomdnolen: on clj or cljs or both or what?
21:10coventryI just watched Stuart Halloway's Clojure Tips talk from earlier in the year, where he said that debugging facilities in clojure are lacking, but traditional debugging tools are probably not what's needed. Has he written anything about what's needed instead?
21:10bbloomdnolen: oh haha http://dev.clojure.org/jira/browse/CLJ-15
21:10bbloomdnolen: apparently rich himself reported this in 2008
21:10dnolenbbloom: ok, yeah Christophe's point is interesting
21:11bbloomdnolen: i know that we do a mix of hash code caching strategies. sometimes caching on use w/ mutation, sometimes cashing on construction. is there any reason not to universally cache on construction?
21:11dnolenbbloom: how can you can cache lazy values? (maybe there's a fancy way?)
21:12bbloomdnolen: ignore christophe's comment for a moment, i'll return to that
21:12bbloomdnolen: i mean for vectors, PAM, PHM, etc
21:13dnolenbbloom: for literals makes sense, not sure about anything else, would need to benchmark
21:13dnolenbbloom: nice to avoid that cost until needed
21:13dnolenbbloom: if you do it for conj you're probably good anyway
21:13bbloomdnolen: right, but pay a test against -1 later. not sure how that balances out in practice
21:14dnolenbbloom: so literals + conj covers most cases I think.
21:14dnolenbbloom: not sure about assoc ..., nor pop, or stuff like that though?
21:14dnolenbbloom: anyways fancy hashing tricks is outside my knowledge
21:14bbloomdnolen: nah, i think the mutation thing makes the most sense
21:15bbloomanytime you do anything, you create new nodes w/ -1
21:15bbloomdnolen: and then you just decorate all the interior nodes of the tree w/ that caching/hashing strategy
21:15bbloomso if you conj, you get a -1 hash again, but you only need to walk the top level of the tree, and the modified branch
21:16dnolenbbloom: ok right, so this why not done, a lot of work for every data structure?
21:16dnolenwe have a lot
21:16bbloomdnolen: yeah, it's just a big change
21:16bbloomseems like it could be a big win for some use cases tho
21:17bbloomin particular, i've had to twist my code a little bit to avoid "changing" things
21:17bbloompartly because of GC concerns, but more b/c equality gets slow again
21:17bbloomhell, i'd really love to wrap every persistent structure in a mutable cell, then garbage collect and compact things :-)
21:20bbloomdnolen: i ran in to an issue once where i had a largely redundant data structure (like the cljs namespaces atom) and printing/reading it used absurd amounts of memory
21:21bbloomdnolen: would be super awesome if you could recover lost structural sharing
21:22clj_newb_2345if everything is value
21:22clj_newb_2345can't you recover structural sharing by calculating the sha256 sum of every node
21:22clj_newb_2345then having a hash table of those hashes ?
21:22bbloomclj_newb_2345: you can do something like that, but the particular approach would be a bit different in order to perform well
21:23clj_newb_2345bbloom: indeed, on every object construction, looking up "does this hash exist" is probably a bit too much
21:24bbloomdnolen: oh, i realized why incremental hashing is a bit tricky: you need a hash algorithm that will compose correctly. if you have PAM and PHM interior nodes w/ non composing hash functions, then you wouldn't be able to do proper cross-implementation comparisons
21:24bbloomclj_newb_2345: there are systems that do that: http://www.meta-environment.org/Meta-Environment/ATerms
21:24bbloomclj_newb_2345: but not ideal, i think
21:25clj_newb_2345though given CLojure's meta data support, this is tempting
21:25clj_newb_2345this also does make sense to go into the gc layer
21:25clj_newb_2345the gc has to touch all the objects anyway; so while there, why not look for structural sharing
21:25dnolenbbloom: it just sounded tricky to me period, but OK
21:26bbloomdnolen: you need an associative hash function
21:26clj_newb_2345there is the downside that this requires all "hashed" objects to be immutable; since changing object -> changing hash -> might have to change a chain of hashes
21:26bbloomafter that, i think it's relatively straightforward
21:26bbloomclj_newb_2345: i consider that an advantage :-)
21:27clj_newb_2345I like immutable too
21:27clj_newb_2345but occasionally, I like mutability
21:27clj_newb_2345i.e. why I use clojure rather than, say Haskell
21:32callen90% of the time I've seen somebody say they needed mutability or mutable global state for something, they haven't.
21:32callenbut the 10% is still there.
21:33bbloomsee also http://en.wikipedia.org/wiki/Hash_consing
21:54ddellacostagood morning
22:01callenddellacosta: morning.
22:01ddellacostacallen: morning, how goes it?
22:01ddellacostaer, evening? I guess
22:02ddellacostaI SEND YOU GREETINGS FROM THE FUTURE
22:02seangrov`ugt
22:02seangrov`~ugt
22:02clojurebotugt is Universal Greeting Time: http://www.total-knowledge.com/~ilya/mips/ugt.html
22:04mmarczykdnolen: bbloom: re: incremental hashing, cgrand's comment on CLJ-15 about needing to force lazy seqs placed in vectors or maps applies; if that's unacceptable in general, something like Mark Engelberg's wrapper (in instaparse) can be used where it is; anyway, I've wanted incremental hashing of all PDSs for a while now and I'm totally up for implementing it in whichever fashion (and before that, spending time to figure out a
22:04mmarczyk"cancellable" hash combiner)
22:04ddellacostaseangrov`: that's awesome, didn't know about that. I guess I was right in the first place.
22:05bbloommmarczyk: aah now i understand his comment
22:05bbloomhmmm
22:05bbloomyeah, that is a pickle
22:05mmarczykfinishing sentence above, that's right after I finish my current secret PDS impl project, which I'm hoping will be of use to certain implementers of pretty printing libraries :-)
22:06mmarczykit is, unfortunately
22:06bbloommmarczyk: :-D
22:06mmarczyk:-)
22:06mmarczykit is, unfortunately
22:06mmarczykfor example it means no infinite seqs in vectors
22:07bbloommmarczyk: yeaaah… i've always been kinda conflicted about how vectors & seqs work w/ respect to equality
22:07mmarczykof course if anybody ends up hashing a vector with lazy stuff inside they'll force it anyway, but apparently often enough that doesn't happen
22:07bbloommmarczyk: it's convenient as hell that seqs = vectors
22:07bbloombut also kinda strange & wrong feeling
22:08mmarczyknotably split-at / split-with couldn't possibly work the way they do now
22:08bbloomyeah, it's kinda this weird compromise
22:09bbloomlazy seqs are not always "values"
22:09bbloomin fact, they are explicitly non-values, since they contain thunks
22:09mmarczykyes, Clojure's notion of equality is a bit funny
22:09mmarczykwell, I don't know if the fact there's a thunk inside makes it a non-value
22:10mmarczykbut the potential infinity sort of sounds like a it's on the co- side of the relevant foo / cofoo divide :-P
22:10ddellacostaIs there any benefit to (or even any method for) using austin over piggieback if you are connecting to an already-started-app from an already started repl, the two being in different threads (that is, in contrast to the default example in the austin docs for connecting to an app)?
22:10bbloommmarczyk: heh yeah
22:10bbloomddellacosta: cemerick is the man to ask
22:11ddellacostabbloom: true, thanks
22:11ddellacostafigured I'd throw it out there though, in case anyone else had an idea
22:12cemerickddellacosta: didn't you just describe the "browser-connected REPL" use case, described in the README (vs. the "project REPL")?
22:13cemerick(all this nomenclature needs serious work) :-P
22:13mmarczykbbloom: thanks for the anf link btw, love the function names :-) I'll read it properly this weekend, along with the Flanagan et al paper hopefully
22:13bbloommmarczyk: my pleasure! i haven't read the flanagan stuff at all :-/
22:14ddellacostacemerick: um, yes, exactly--the big difference between your example and my use-case being that I have a script which starts up my app
22:15mmarczykbbloom: re: lazy seqs, we'd have to give up value-based equality completely, not just equality with vectors, to avoid forcing to hash, which I guess is a complete no-go given the pervasive hidden (as in not explicitly asked for) laziness in the seq library
22:15cemerickddellacosta: well, cljs' stock browser-REPL has a number of limitations that I used to hit regularly. Can't run multiple REPLs out of the same backend, need to shuffle port numbers around frequently, :cljs/quit shuts down the HTTP server until the next REPL session is created, etc.
22:15ddellacostacemerick: and as far as what I've been able to figure out, it seems like I need to be running in the same thread to get the nrepl configuration working right, in terms of how values are set and where they are accessible. So I wondered if there was any value in it, since the default piggieback config is working pretty damn well (did you make that more robust? Haven't dug into the code yet).
22:16cemerickddellacosta: not sure what you mean re: in the same thread?
22:16bbloommmarczyk: yeah, i think it's past the point of no return. there isn't any way to solve this problem (that i can think of) that wouldn't involve dramatic sweeping changes to how laziness & evaluation works
22:16dnolenwow after core.async, the Promise/Rx dichotomy is JS is truly painful
22:16dnolens/is/in
22:16bbloomdnolen: i believe you, but i'm curious what motivated you to say that
22:17mmarczykdnolen: you mean core.async is a sort of a de-numbing agent? :-P
22:17ddellacostacemerick: so, it's entirely likely I'm confused about something. But the example you have for the browser-connected repl assumes you are starting your app from the repl, so you have access to the loaded namespaces/values in that repl
22:17dnolenbbloom: I was just toying around with some benchmarks between core.async and when.js one of the fastest Promises/A+ libraries
22:17dnolenbbloom: and realizing so many of the things I've done are nearly impossible to express in terms of Promises.
22:18dnolenand how wasteful Promises are, it's a one off
22:18bbloomdnolen: yeah, i found that you needed a pretty large promise library for common patterns. things that are pretty easy with multiplexing
22:19bbloomdnolen: when i had no choice but to do js/coffee, i preferred async.js (which is callback combinator functions)
22:19cemerickddellacosta: that's just the simple base case, where the REPL server port and session number are in-process, and so can be super-easily templated into your app
22:19bbloomit was basically the same as promises, but without the refied objects & with saner error handling semantics
22:19cemerickNothing there is thread-related, tho.
22:19seangrov`,(take 5 (iterate 10))
22:19clojurebot#<ArityException clojure.lang.ArityException: Wrong number of args (1) passed to: core$iterate>
22:20seangrov`,(take 5 (iterate inc 10))
22:20clojurebot(10 11 12 13 14)
22:22ddellacostacemerick: hmm, okay, I must be getting confused. To try to explain more completely, following the example for the browser-connected repl, when I call browser-connected-repl-js from cemerick.austin.repls in my routing, I get nil. I thought this was because I wasn't setting cemerick.austin.repls/browser-repl-env from within the same thread--my loaded ring app was not started via repl.
22:22cemerickddellacosta: Just FWIW, if what you're doing now is working, carry on :-) Austin is by no means intended to be a the end-all-be-all of cljs REPLs.
22:23ddellacostacemerick: oh, no--I just wanted to see if I wasn't mistaken about the use case! piggieback is definitely working, but I want to explore all the options so I can figure out what is possible, and also try to help if I can provide another way to smoothly get more use-cases working for the CLJS eco-system.
22:24ToBeReplacedcemerick: is there progress on strint/<< making it into core?
22:24ddellacostacemerick: I figure, the more I am doing some yak-shaving to get my specific way of working going, if I can even just contribute some feedback and docs it will be useful to everyone.
22:24cemerickddellacosta: if b-c-r-js is returning nil, then you haven't set the cemerick.austin.repls/browser-repl-env atom yet/properly
22:25cemerickdefinitely nothing thread-related there
22:26cemerickToBeReplaced: Nope, not going to happen. I've been meaning to start distributing it in its own library, since right now it's basically marooned in incubator
22:28ToBeReplacedcemerick: is there discussion somewhere? anything going to happen in its place?
22:28ddellacostacemerick: right, but it seems like, based in the example, it is assumed that you load repl-env in your running app from the same thread that you connect your repl, and therefore they have access to the same values. Because browser-repl-env is an thread-specific atom, if you don't start your app from the same thread you've set cemerick.austin.repls/browser-repl-env in, you can't access it when generating a script
22:28ddellacostain the app. Does that make sense, or am I totally off?
22:30ddellacostacemerick: argh, wait, I'm realizing the flaw in what I'm saying, hold on
22:30cemerickToBeReplaced: The last discussion of string interpolation being in core was here in irc years ago. I would be very surprised if something like it ever landed in core.
22:30cemerickddellacosta: yeah, you're thinking of vars and binding
22:30ddellacostacemerick: yes, not atoms. D'oh. Sorry for the confusion!
22:30ToBeReplacedcemerick: thanks
22:33cemerickddellacosta: gots to run. Ping later if you're still having issues :-)
22:33ddellacostacemerick: thanks for being my sounding-board so as to let me talk myself into figuring out my mistake…haha. Thanks, cheers! I think I'm good for now. ;-)
22:49seangrov`Should ISeqable be extended to [object NodeList]?
22:58dnolenseangrov`: don't do it. just pass array likes into prim-seq
23:02seangrov`dnolen: Ah, that works nicely, thanks
23:08dnolenseangrov`: yeah it's just too easy to miss something, prim-seq covers the bases
23:08cgaganyone seen "peerUri undefined" when trying to connect the clojuresript browser repl?
23:08dnolencgag: you cannot use file:// protocol, are you going to localhost:9000/foo.html ?
23:09cgagi am
23:13cgaghttps://www.refheap.com/17991
23:13cgagbasically all i have
23:13cgagthe alert goes off
23:13cgagthe first one at least
23:14dnolenquick post on latest core.async perf enhancements http://swannodette.github.io/2013/08/23/make-no-promises/
23:30dnolencgag: sounds like you're not specifying a version of ClojureScript in your project.clj
23:31cgagi just have lein-cljsbuild 0.3.2 and have been using that
23:37cgagit does seem to have generated a repl/clojure/browser folder
23:37dnolencgag: specify a version, you can never trust what cljsbuild pulls in
23:37cgagi wonder if this is making some invalid assumptions about my directory structure
23:37dnolencgag: 1859 is the latest
23:43shaungilchristdnolen: awesome article noticed a typo in last sentence though - extra "the" after "providing"
23:44dnolenshaungilchrist: thx
23:44shaungilchristyour blog is a beacon of hope in a sea of callbacks
23:48Apage43i..
23:48Apage43man.
23:50cgagdnolen: no dice :\
23:55cgagmy project file: http://pastebin.com/TiVVmDSB