#clojure log - Sep 07 2014

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

0:12 babygau: http://stackoverflow.com/questions/25706915/explain-clojure-map-reducer-implementation

0:15 BAMbanda: I'm having trouble installing lein, I'm on arch linux and got everything from the most updated community package

0:15 http://pastie.org/9533132

1:29 justin_smith: john2x: the require forms will work, within the ns the ns form defines

1:29 john2x: so any :as aliases only work in that specific ns

1:30 babygau: http://stackoverflow.com/questions/25706915/explain-clojure-map-reducer-implementation

1:33 justin_smith: babygau: f1 is the function called for 0 args

1:33 it is using the multi-arity feature of fn

1:34 so I would guess that (f1 ret (f k v)) should evaluate to 0 1 or 2

1:34 ,([:a :b :c] 1)

1:34 clojurebot: :b

1:34 babygau: @justin_smith I got that line of code, but what I don't understand is why [ret k v] is placed in the beginning of a `form`

1:35 justin_smith: it is definitely odd, code, that is hard for me to read after a few ciders

1:35 sorry

1:35 babygau: look at `rfn` macro

1:35 justin_smith: (cider as in the drink, not the emacs clojure lib)

1:35 ret k and v are the three things that form can return

1:35 as I showed above, a vector as an IFn returns the item at the index supplied

1:36 so f1 must end up returning 0, 1, or 2

1:36 tadni_: Cider typically has alcohol?

1:36 babygau: @justin_smith: so is it sort of `destructuring form`???

1:36 lazybot: babygau: Yes, 100% for sure.

1:36 justin_smith: tadni_: the kind I just had did

1:36 babygau: it is a shortcut for get

1:36 ,(get [;a :b :c] 2)

1:36 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

1:37 tadni_: justin_smith: But not typically?

1:37 * tadni_ doesn't think he's ever had cider of any sort.

1:37 justin_smith: tadni_: in my town, if the menu says "cider" it is probably alcoholic, but my town is full of hipsters, so who knows what typically means

1:37 tadni_: Says it's unfermented, so I'd assume no.

1:38 justin_smith: San Fran?

1:38 justin_smith: ,(get [:a :b :c] 2)

1:38 clojurebot: :c

1:38 justin_smith: tadni_: Portland Oregon

1:38 babygau: @justin_smith: so this is a `shortcut`????

1:38 tadni_: justin_smith: That would've been my second guess. :^P

1:38 justin_smith: babygau: in the same sense that a map or keyword as function is a shortcut

1:39 babygau: they all end up invoking get

1:39 ,(= (get {:a 0 :b 1} :b) ({:a 0 :b 1} :b) (:b {:a 0 :b 1}))

1:39 clojurebot: true

1:40 tadni_: For living in such a meh-city tech wise, I was shocked to hear we have a Clojure Meetup. (St.Louis)

1:40 babygau: @justin_smith: oh my god, I just test it with repl

1:40 justin_smith: weird, huh

1:40 babygau: @justin_smith: and you're right

1:40 justin_smith: everyone acts like me being right would be surprising or something!

1:40 babygau: @justin_smith: I don't need to use `get` method with `:keyword`

1:41 ([:a :b :c] 2)

1:41 justin_smith: just showing that keywords, maps, and symbols, and vectors all end up invoking get when used as functions

1:41 right

1:42 if you wanted to invoke clojurebot, you can use ,

1:42 for lazybot use & or ##

1:42 tadni_: justin_smith: "Cider or cyder is a fermented alcoholic beverage made from the unfiltered juice of apples."

1:42 Who knew? I didn't.

1:42 justin_smith: tadni_: thats what I drank, yup

1:42 babygau: @justin_smith: you're awesome!

1:42 ,([:a :b :c] 2)

1:42 clojurebot: :c

1:42 dorkmafia: does my version of java matter when using clojure? i'm on 1.6 and was thinking of upgrading to 1.7 to get the usage of a library

1:43 justin_smith: though in some places (like Vermont, where I was as a child) cider means an unfiltered raw juice

1:43 lpvb: dorkmafia: no

1:43 justin_smith: other places its a juice served hot with spices

1:43 lpvb: dorkmafia: only matters if you try to use java classes not provided with an older java version. Min version is 1.6 iirc

1:43 dorkmafia: justin_smith: hot apple cider vs cider vs hard cider

1:44 babygau: @justin_smith: can you please answer my question on #stackoverflow. I'm happy to check your answer

1:44 jethrokuan: guys i gave a question

1:44 justin_smith: dorkmafia: the thing is, in different regions, each is just called "cider" with no qualifying adjective. It varies.

1:44 tadni_: justin_smith: We used to have hayride things as a kid, and they handed out cider to minors ... so yeah, I'm guessing it wasn't alcholic. Never had it though... so, who knows.

1:44 jethrokuan: can i type code here?

1:44 justin_smith: babygau: sure thing

1:44 lpvb: not if it's more than one line

1:45 justin_smith: jethrokuan: for more than a line or two, use refheap.com or a github gist please

1:45 ~paste

1:45 clojurebot: paste is https://refheap.com/

1:45 jethrokuan: i'm on my phone so ._.

1:46 justin_smith: dorkmafia: also, with the jvm, backward incompatibility is extremely rare, there is a low probability you would break anything by upgrading to 1.8 right now

1:46 dorkmafia: are there any nice tutorials on wrapping functionality of a jar in clojure? I'm really new to clojure so even just some good tutorials :)

1:46 justin_smith: dorkmafia: just use interop first, if it is a huge pain, you can adapt some of your code into a wrapper lib

1:46 dorkmafia: but step one is learning interop regardless

1:46 dorkmafia: justin_smith: probably break everything adobe related lol

1:47 justin_smith: dorkmafia: I sincirely doubt it, but you can have parallel jvm installs and select which one you need for each program anyway

1:49 dorkmafia: i was looking for good xmpp lib

1:49 jethrokuan: https://www.refheap.com/89939

1:50 i'm kinda confused as to how the loop works

1:50 i thought locals don't vary so why is the value of sum changing

1:50 justin_smith: jethrokuan: the function args are different

1:50 recur sets the new values for the arg

1:51 most functions will return a different value when provided different args, right?

1:51 jethrokuan: so recur will set a new value to the function args?

1:52 justin_smith: the function is called again, with new args

1:52 it's not mutating, it's calling itself (in a special way that does not consume stack frames)

1:53 jethrokuan: but here (+ sum x) is called, which returns an entirely new value not bounded to any locals that the function uses

1:54 justin_smith: ?

1:54 it's saying: return the value of calling this function with these args

1:55 there is no mutation there

1:55 jethrokuan: let me ponder over that for a while

1:55 * tadni_ plans on having his introductory blog post on learning clojure/study-plane, by tuesday. :^)

1:56 justin_smith: cool

1:56 good luck

1:56 jethrokuan: oh!!

1:58 so if the function takes two args the recur must return two as well

1:58 justin_smith: it must take two

1:58 you can only return one value, no matter what

1:58 narayana: i am happy with o really clojure programming

1:58 jethrokuan: ah yes terminology

1:59 i'm trying to go through the joy of clojure

1:59 justin_smith: if you haven't programmed in a lisp before, joy of clojure will be a challenge

2:00 it's a great book, but it's not an introductory level book imho

2:00 ~books

2:00 clojurebot: books is book

2:00 justin_smith: ~book

2:00 clojurebot: book is programming clojure

2:00 jethrokuan: i've kinda browsed through programming clojure by pragprog

2:00 narayana: my best friend is great lisp programmer

2:00 justin_smith: narayana: some day I hope to be one

2:01 narayana: you will clojure is best way for that

2:01 jethrokuan: i feel that the joy of clojure has taught me way more already

2:02 though i'm still dealing more with clojurescript/om

2:02 narayana: for me sometimes i using facebook for uploading examples with screenshoots

2:02 but yes blog is ok

2:03 these days i am reading book clojure for machine learning and making examples

2:04 some basic stuffs with core.matrix and clatrix

2:06 dorkmafia: justin_smith: how would I run chrome in 32 bit mode?

2:06 justin_smith: dorkmafia: I actually don't even know. That's pretty OS dependent isn't it?

2:07 dorkmafia: yah i think there is a setting I can set some where lol

4:33 john2x: is it just me or does cider not follow the :init-ns option in project.clj? When I `cider-jack-in` in my project.clj, it starts at the `user` namespace. But when I do `$ lein repl`, it starts in namespace specified by :init-ns

4:34 zeebrah: is there a reason i can't have cider-mode enabled in the cider repl? it wont evaluate anything after i enable clojure-mode in the repl

4:37 john2x: zeebrah: if you just want to have clojure-mode's font-locking in your cider-repl, try (setq cider-repl-use-clojure-font-lock t)

4:37 zeebrah: john2x: yep! you guessed what i wanted. I'll try that out, thanks

4:39 doesn't look like that function exists in the latest cider though, oh well

4:41 john2x: zeebrah: strange, it's in their readme... and i'm on the latest version as well and it exists for me (it's a var btw)

4:41 zeebrah: yeah i realised after i wrote (that it's a var), in any case it didn't have any effect

4:48 it's kinda bizarre that the default behaviour is not to fontlock in the repl

5:24 https://github.com/clojure-emacs/cider/issues/749 <-looks like this is the bug i'm running into

5:26 and another bug which is more serious is that i dont get a stacktrace buffer popup either. it just dumps the exception into the repl at the point :s

6:01 john2x: zeebrah: re: the stacktrace buffer, what is `cider-show-error-buffer`'s value?

6:09 zeebrah: john2x: t. it shows the error buffer, just not the stacktrace in a seperate buffer. http://i.imgur.com/cFP8UtI.png

6:12 john2x: zeebrah: oh yeah, I get that sometimes too. weird.

6:13 are you using 0.8.0-SNAPSHOT for cider-nrepl in profiles.clj?

6:15 zeebrah: john2x: yep

6:15 i just updated after seeing the clojure-mode 3.0 ann heh

6:15 so far the experience has been not so great :/

6:47 hugod: zeebrah: is that a repl outside a project with lein 2.4.3?

6:48 zeebrah: hugod: nope, just using cider-jack-in - there isn't a project

6:49 noncom: anyone using ccw here?

6:49 what about java 8 and eclipse luna ?

6:49 hugod: zeebrah: it is a lein issue - https://github.com/technomancy/leiningen/issues/1625

6:51 zeebrah: hugod: oh. okay :)

6:51 noncom: clgv: hello, are you here? i have a little question on ccw if you maybe already know.. ^^

6:52 zeebrah: hugod: so do you know of a good fix or isn't there one yet?

6:53 hugod: zeebrah: downgrade lein to a previous version

6:54 zeebrah: hugod: yeah i saw that suggestion earlier but was hoping for something else

6:54 hugod: a new version of lein should be released any day now

6:55 zeebrah: hugod: that fixed my stacktrace problem though. good pick up!

6:56 borkdude: can I express in pristmatic/schema: I want the return value of a function to be a sequence of maps, with arbitrary keys in them?

6:57 hugod: borkdude: [{s/Any s/Any}]

6:57 borkdude: hugod ok

7:06 any advice on using schema's with channel output?

7:08 I guess I'll use a transducer as a validation fn

7:14 cfleming: hugod: Hi, the other day you asked about how Cursive was more sophisticated than cider, and I'd just gone to bed

7:16 hugod: Basically Cursive actually analyses syntax, so it resolves symbols in the editor from source

7:17 hugod: Since it also indexes, this allows lots of cool stuff - symbol rename, find usages, navigation etc

7:17 hugod: This all works for global symbols (vars) and local bindings.

7:18 hugod: Also things like auto-require and automatically building scaffolding for proxy/reify/deftype/defrecord forms

7:19 hugod: It'll support extracting and inlining methods shortly, which you need symbol resolution for.

7:20 hugod: Since it's based on source, all this works with no REPL running.

7:21 hugod: The main issue with it is that it needs understanding of the syntax of forms, and the syntax in Clojure is extensible - internally Cursive is based around an extension API that I'll be opening up so others can add support for libs they use, or for internal APIs.

7:22 hugod: Basic support (symbol resolution) is pretty trivial to add, some more sophisticated libs (typed clojure etc) need more work.

7:23 hugod: cfleming: interesting that it works with no repl

7:23 borkdude: the docs here https://github.com/Prismatic/schema/ talk about s/validator for performance

7:23 maybe I'm overlooking something, but I can't find it

7:23 cfleming: hugod: Yeah, it's all based on static source analysis

7:23 hugod: Which has its ups and downs

7:24 * beamso is enjoying using cursive

7:24 hugod: cfleming: clj-refactor supports some of those things, and there are plans to use tools.analyzer to enable things like function extraction (not sure where that work is at)

7:25 cfleming: hugod: yeah, clj-refactor still has some stuff that Cursive doesn't, but nothing difficult to add, just a matter of time.

7:25 hugod: Cursive now has local binding extraction which is really nice.

7:26 hugod: yeah, completion includes local bindings in cider now

7:26 cfleming: hugod: But the auto-import is probably my favourite recent feature - type str/tr<complete> and [clojure.string :as str] gets added to your requires when "trim" is completed.

7:27 hugod: right - clj-refactor adds auto-import too

7:27 cfleming: hugod: But only for namespaces you've configured in .emacs, right?

7:27 hugod: indeed - cursive learns these itself?

7:27 cfleming: hugod: Yup

7:28 As long as you have that ns imported with that alias somewhere in your project.

7:28 hugod: how do you distinguish the author/project style from the style of some random clj file that you have open?

7:28 oh, it is based on files from a single project?

7:29 cfleming: Right, although since I know all the namespaces I'm going to add a version that pattern matches too, if there's no matching explicit prefix.

7:29 i.e. it'll match str to clojure.string and propose it since clojure.string has a var starting with tr

7:30 It'll only do that if there's no exact match.

7:30 hugod: interesting - I wounder if cider could use completion to do something similar

7:30 cfleming: I totally recommend it if you can - it's great.

7:31 I'm going to add things like move function from one ns to another soon, that will add and remove the relevant ns decls to the source and target ns

7:31 Cursive also marks unused local vars, and will shortly mark unused imports/requires

7:32 borkdude: in Prismatic Schema, is there something to turn on ^:always-validate for every s/defn during development?

7:37 cfleming: beamso: Glad you're enjoying Cursive :-)

7:37 hugod: cfleming: so mostly advantages stemming from analysing the code iiuc

7:37 Sh00ck: Hello guys, i'm new to clojure (i enjoy it so far). why can't i put a function "under" the call? (IMG: http://url.udev.io/llp9f)

7:37 cfleming: hugod: Yeah, that's the main difference.

7:38 It has other advantages - it inherits IntelliJ's debugger support, which is really nice

7:38 hugod: cfleming: yeah, debugger support can certainly be useful

7:39 cfleming: hugod: And the IntelliJ inspection infrastructure is nice, it'll allow me to do Kibit/Eastwood right in the editor

7:39 hugod: with quickfixes etc

7:40 hugod: I'll be presenting about all this at the conj if you're there, we should get a beer if so

7:40 beamso: Sh00ck: because you're calling the function before you've defined it

7:41 hugod: cfleming: probably will not make it this year :(

7:41 cfleming: hugod: bummer, next time

7:41 Sh00ck: beamso: yeah, but in example Go or Rust it works :o

7:42 hugod: cfleming: thanks for going through these - interesting to hear what you are up to with Cursive. I should probably fire it up and give it a try :)

7:43 cfleming: hugod: Hehe, I'd be interested to know what you think!

7:43 hyPiRion: Sh00ck: You can if you do (declare function-name) at the top – but yeah, it's a weird thing you get used to

7:44 beamso: Sh00ck: true, but it may not work in a shell script or in ruby outside of a class

7:44 hyPiRion: Sh00ck: I think it's done that way to motivate simplicity

7:44 hugod: cfleming: of course

7:44 Sh00ck: hyPiRion: thanks! it works :)

7:52 kitallis: is there a better way to do this http://pastie.org/9533650?

7:56 lavokad: using reduce

8:04 kitallis: lavokad, for that I'll have to do a map-indexed

8:10 lpvb: DDDDDDD"A

8:13 lodin: kitallis: If you don't want to rewrite it using reduce etc you can still remove the variable "no" and check for (seq (rest coll)) instead.

8:14 tobik: kitallis: you don't need map-indexed if you use reduce, see http://pastie.org/9533673

8:15 kitallis: tobik, aha

8:15 of course

8:16 lodin, that makes sense too

8:16 thanks

8:17 lodin: kitallis: I don't see any reason to increment i manually though. You only using it in some-fn and i does not effect the next iteration.

8:17 *affect.

8:19 kitallis: so (map-indexed some-fn coll) looks perfect for the job, no?

8:21 kitallis: lodin, well, some-fn returns a map, which needs to be merged back in

8:23 lodin: kitallis: Right. So try to move out i, some-fn, and coll from make and see what's left.

8:23 kitallis: this was my other version: http://pastie.org/9533686

8:25 lodin: kitallis: Try replacing (map-indexed vector coll) with (map-indexed some-fn coll) and adjust reduce accordingly.

8:36 kitallis: lodin, i've got it, just struggling with some syntactical mess, one moment

8:47 wjlroe: Is there a protocol I can extend on a record to provide toString on that record? I currently have a (show) function in my own protocol but (str) doesn't know about it obviously

8:49 kitallis: http://pastie.org/9533727

8:49 no idea why i couldn't get the reader macro form working

8:49 lodin, thanks a lot!

8:49 wjlroe: Ah the protocol is Object, why didn't I think of that?

8:50 lodin: kitallis: Nice.

8:51 kitallis: You don't need to provide the fn though. Just pass some-fn.

8:52 All you need is (reduce {} (map-indexed some-fn coll)).

8:52 err, (reduce merge ...)

8:53 kitallis: lodin, cool

9:20 gfredericks: wjlroe: not technically a protocol; Object is special-cased in defrecord (see the docstring)

9:25 wjlroe: gfredericks, ok, I can't see any mention of Object in the docstring and the implementation is a wall of code so that's not clear to me

9:28 gfredericks: ,(-> #'defrecord meta :doc (->> (re-find #".{10}Object.{10}")))

9:28 clojurebot: "ethods of Object. Note tha"

9:28 gfredericks: wjlroe: ^ it's there

9:29 wjlroe: oops missed it

9:30 My mistake for attempting to multi-task

9:59 J_Arcane: I seem to be a bit stuck on this: http://clojurescriptkoans.com/#destructuring/3

10:01 I tried (str first-name " " last-name " aka" (reduce #(str " " %1 " aka " %2) aliases)) but I seem to get an extra space after the first "aka" so it fails.

10:01 justin_smith: J_Arcane: I think you want to use clojure.string/join

10:01 instead of that reduce

10:03 another bonus, join uses a StringBuilder, which will perform much better than repeated calls to str where the previous partial string is never used again

10:03 maxpn: how to refresh dependencies in project.clj? like npm update

10:04 justin_smith: maxpn: either restart your process, or use alembic.still

10:04 maxpn: or do you mean get newer versions? in clojure it's best to ask for a specific version, you can use lein ancient to see what could be upgraded

10:06 maxpn: yes. for example I have [org.clojure/data.json "0.2.4"] in my project.clj . is there easy way to know laterst version 0.2.5?

10:06 justin_smith: lein ancient

10:06 maxpn: is it separate tool?

10:07 justin_smith: it comes with lien

10:07 you literally go to the project directory and run "lein ancient"

10:07 that's the command

10:07 maxpn: 'ancient' is not a task. See 'lein help'

10:07 jeffterrell: Actually I think it's a plugin.

10:07 justin_smith: oh, it must be a plugin

10:07 jeffterrell: Add this to your ~/.lein/profiles.clj

10:07 [lein-ancient "0.5.5"]

10:08 In the [:user :plugins] spot.

10:08 maxpn: thank you!

10:08 jeffterrell: I found that plugin a couple weeks ago. Very useful!

10:09 justin_smith: I got suspicious of upgrading, between clojure.data.json and the various emacs modes for clojure

10:11 maxpn: is there an easy way to add incremented version number to uberjar?

10:11 build number or git hash

10:12 I'd like to have a build number in my web app

10:13 automatically incremented number.

10:13 justin_smith: maxpn: there is a lein plugin for something like that, my google-fu is failing though

10:14 https://github.com/relaynetwork/lein-release

10:15 maxpn: yes, got it.

10:15 thanx

10:15 jeffterrell: The wonderful world of lein plugins. :-)

10:15 J_Arcane: justin_smith: Thanks, that worked: (clojure.string/join " " (list first-name last-name "aka" (clojure.string/join " aka " aliases)))

10:16 justin_smith: jeffterrell: maxpn: lein is where most dev tooling happens (that isn't editor specific at least)

10:16 J_Arcane: cool, that looks about right, yeah

10:17 jeffterrell: I found a plugin the other day that made it super easy to deploy my backend API server as an Ubuntu service. I think it was called init-script. I love not having to worry about that sort of stuff.

10:21 maxpn: but how can I get project.clj/version number at runtime?

10:21 justin_smith: maxpn: it will be in the pom.xml - I know there is a way to access that, one moment

10:23 maxpn: pom.xml? i don't have that in my project.

10:24 justin_smith: maxpn: lein jar / lein uberjar generate one

10:24 and if you aren't using one of those to deploy, you are doing it wrong

10:26 maxpn: try (System/getProperty "myproject.version")

10:28 with myproject being changed to the project version of your project, of course

10:28 maxpn: I could just create and update myproj/version.clj: (def VERSION "1.2.3 build NNNN") every time I do uberjar

10:28 justin_smith: maxpn: try the getProperty thing first

10:28 maxpn: but I hope there already is a plugin for that/

10:29 justin_smith: oh, wait - the getProperty thing only works from within lein

10:29 check this thread https://groups.google.com/forum/#!topic/leiningen/7G24ifiYvOA

10:29 PeakCode: lein pom

10:30 justin_smith: PeakCode: that generates a POM, but that's not what we are talking about

10:30 PeakCode: OK, sorry.

10:31 justin_smith: maxpn: if you create a file with those contents, put it under resources rather than source

10:31 since it's data, not code

10:52 bounb: hm, strange error when i try "lein koan run", any clues? https://www.refheap.com/89957

10:54 justin_smith: bounb: looks like it is related to the whole https for maven fiasco

10:54 bounb: i see... what to do?

10:55 justin_smith: you could downgrade to 2.4.2 temporarily "lein upgrade 2.4.2"

10:55 bounb: thanks!

10:57 justin_smith: oh, i am on 2.4.2...

10:57 justin_smith: ugh

10:57 dunno then

10:57 try 2.4.3 just for getting the deps, then switch back?

10:58 bounb: k

10:58 justin_smith: via lein deps of course

11:00 bounb: no dice, lein deps gives me same error

11:00 justin_smith: maybe clojure koans is messed up? I am going to try

11:01 bounb: cheers

11:01 PeakCode: I think the problem is with the JDK. Try using another one.

11:02 justin_smith: bounb: lein deps finds all of it on the first try here (2.4.2)

11:02 bounb: good idea. using Java 1.7.0_65 OpenJDK 64-Bit Server VM atm. i'll try 1.8

11:02 justin_smith: I am using oracle jdk 1.8

11:02 bounb: thx, will upgrade

11:08 still no good, although it's now complaining about clojars.org rather than maven.org

11:08 i refuse to believe it's an issue caused by OpenJDK vs Oracle...

11:26 technomancy: bounb: it could be OS-installed jdk vs manually-installed jdk

11:26 the OS-provided one usually integrates better with the existing certificate store

11:28 bounb: i just installed them with my package manager, i have openjdk 7 and 8, seems to be same issue with both

11:29 technomancy: it could be a proxy trying to MITM you or something

11:30 hyPiRion: bounb: it's a CA-cert store issue iirc

11:30 bounb: i think that's it hyPiRion, was reading some github issues

11:30 not sure what to do though

11:32 hyPiRion: bounb: try to install ca-certificates for java. It's e.g. ca-certificates-java for debian/ubuntu

11:32 so `sudo apt-get install ca-certificates-java`

11:33 bounb: i had that, but i reinstalled it and it works. thanks!

11:34 hyPiRion: ah, nice

11:38 bounb: clojure is just quality from the ground up, community n all

11:44 justin_smith: we try

11:45 dbasch: and catch

11:45 * dbasch ducks

11:46 * justin_smith quacks

11:46 J_Arcane: I'm impressed by the fact that Clojure seems the only Lisp community that understands the value of interactive learning tools. :P

11:46 dbasch: (= (type justin_smith) Duck)

11:46 justin_smith: J_Arcane: dunno, racket may be superior onthat account

11:47 J_Arcane: racket was designed from the beginning to be a teaching / learning language

11:47 J_Arcane: justin_smith: DrRacket is a great starter IDE, but the learning process is still fundamentally "read this book and type in/solve the exercises on your own". By interactive tools I mean stuff like codecademy or the koans.

11:48 justin_smith: 4clojure too?

11:48 J_Arcane: Yeah.

11:50 dbasch: that may be just because is newer, languages invented in the past 5-10 years tend to have good interactive tutorials and tools

11:50 e.g. go, Rust

11:51 J_Arcane: There is a web REPL for Racket, but it's not actually hosted anywhere ATM.

12:23 Methodical: I am trying to test a post to a liberator rest endpoint. I can write a successful test for a get request but I can't seem to manage to pass data to the post. Here is the code I am using https://www.refheap.com/89958

12:29 lpvb: i/w zoom

13:21 jeffterrell: J_Arcane: I've heard that The Little Schemer takes an inductive learning approach, FYI. Though of course that's different than a community valuing the approach.

13:22 J_Arcane: jeffterrell: I've heard good things about it as well, and of SICP.

13:22 jeffterrell: Yeah, definitely SICP. Gotta love that one.

13:23 Methodical: Cool that you're using Liberator. I've heard good things. But I've never used it, so can't help you.

13:23 gtrak: what's the best thing for a CLJS slideshow?

13:24 Methodical: @jeffterrell Liberator is really pretty nice and so far straight forward to use. I think it is more of a ring-mock question that liberator though.

13:25 jeffterrell: gtrak: Kids these days seem to be using reveal.js a lot. (cf. slides.com) Since CLJS has JS interop, you could use that.

13:25 Dunno about a particular CLJS slideshow library/tool though.

13:26 gtrak: I've played with that, also considering gorilla-repl/session.. or just org-mode..

13:26 might be nice to do the whole thing as an om app

13:26 within reveal

13:28 jeffterrell: That would be cool.

13:29 I love the idea of "notebook" style programming that gorilla gives you.

13:30 bounb: the guy that wrote gorilla introduced me to clojure

13:30 is he in here, need to thank him for that

13:30 jeffterrell: Methodical: Nothing looks wrong to me in your example, but there's plenty of stuff I'm not familiar with, not having used Liberator. I do wonder whether Liberator is smart enough to find the request map with a ring `(ANY [_] ...)` endpoint, instead of something more like `(ANY [_ :as req] ...)`, but I dunno.

13:31 justin_smith: (ANY [_} ..) is not ring, it's compojure

13:31 lavokad: hi, in myapp.routes.home namespace there is (defroute myroutes (GET "/page.html" [] (layout/fun))). This file is myapp/routes directory. In my project.clj ring section there is reload? true. When I change layout/fun to something different I have to reload the server to see the changes

13:32 goracio: hi there - who can help with deployment and hosting clojure app ? i think about immutant and using WildFly but there are some questions about it

13:32 justin_smith: lavokad: set your handler by referring to the var

13:32 #'handler instead of handler

13:33 lavokad: the issue is that ring does not see changes to the def unless you set the handler to the var - it does the resolution once and doesn't see any updates

13:34 but it knows that it needs to deref on each request if you use the var form

13:34 hellofunk: i'm trying to get the js equiv of foo.add(bar) in clojurescript. lein compiler reports Unknown dot form of (. foo -add (bar)) -- which is an expansion doesn't make sense since bar is not a function.

13:35 justin_smith: wait, how are you trying to invoke that?

13:36 foo.add(bar) should translate to (.add foo bar)

13:37 hellofunk: justin_smith why not .-add, isn't that for functions?

13:37 justin_smith: .-add is for properties

13:37 ben_vulpes: how does one do the {:keys } destructuring when ones keys are strings and not :keywords ?

13:37 justin_smith: not for methods

13:37 ben_vulpes: :strings

13:37 ben_vulpes: oooooh

13:38 justin_smith: if they had a sense of humor it would be "strings"

13:38 ben_vulpes: i tried that!

13:38 justin_smith: {"strings" [a b c]}

13:38 heh

13:38 goracio: so anyone running clojure sites with immutant ?

13:38 lavokad: justin_smith: however if modify anything in myapp.handler then everything reloads. Moreover, from this moment I can also change myroutes.routes.home and the everything reloads in the browser

13:39 justin_smith: lavokad: so only certain spaces don't get reloaded?

13:41 lavokad: right. and just until I do a change in myapp.handler namespace. From that moment every namespace I change reloading happens well

13:41 justin_smith: very odd

13:42 did you add the new namespaces whil the app was still running by any chance?

13:42 lavokad: So i start the server, go to myapp.handler, put a space there, save, and then it is ok

13:42 justin_smith: no, i didnt

13:44 * tadni_ looks to see if there are any popular blogging platforms for clojure out there. His wordpress.com subscription ends mid-october and he's considering self-hosting.

13:54 dorkmafia: so i'm really new to clojure and trying to figure out how i can make a program taht uses interfaces..

13:56 justin_smith: dorkmafia: do you have a specific java interface that already exists, which you want to implement?

13:56 narayana: i am using emacs live great stuff

13:56 dorkmafia: nope i'm starting from scratch :)

13:56 justin_smith: in clojure, it makes more sense to define a multimethod or protocol

13:56 dorkmafia: i'm going to make a bot and I would like to abstract the messenger client

13:57 justin_smith: unless you need the interface to be callable from java

13:57 yeah, use a protocol or multimethod for that

13:57 multimethods are more flexible (they can dispatch using an arbitrary function on all args, not just the type of the first arg) but protocols perform better

13:58 protocols are trickier in interactive development too

13:58 (that is, they get tricky if you need to redefine them)

13:59 dorkmafia: k thanks i'll check it out more..

13:59 :)

14:07 benmoss: can someone explain to me why `(java.nio.file.Files/createTempDirectory nil)` throws “No matching method”? http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#createTempDirectory(java.lang.String,%20java.nio.file.attribute.FileAttribute...)

14:08 justin_smith: that's a vararg method, right?

14:08 benmoss: yeah, ah that is it again

14:08 justin_smith: you need to pass an empty FileAttribute array as the last arg

14:09 benmoss: whereas in Java passing just null would be fine? `Files.createTempDirectory(null)`

14:10 justin_smith: ,(into-array java.nio.file.attribute.FileAttribute [])

14:10 clojurebot: #<CompilerException java.lang.ClassNotFoundException: java.nio.file.attribute.FileAttribute, compiling:(NO_SOURCE_PATH:0:0)>

14:10 justin_smith: benmoss: right

14:11 benmoss: do you know why Clojure can’t behave the same way? just curious

14:11 justin_smith: because varargs are a fiction

14:11 they are actually an array argument, the javac compiler just pretends they are separate args

14:11 the clojure compiler has no such feature

14:12 benmoss: ah

14:12 justin_smith: similarly, we can't do generic collections in clojure (though due to lisp style typing, we don't notice that)

14:12 benmoss: and in the absence of the argument the java compiler creates an empty array

14:12 justin_smith: benmoss: it takes all args after the nth (which may be none) and makes an array of the proper type

14:12 and that is what the method sees

14:13 benmoss: gotcha

14:13 cool, that helps, thanks :)

14:14 hellofunk: what is the clojurescript equiv of this: document.body.appendChild(renderer.domElement);

14:14 hellofun`: i'm trying this: (dom/appendChild (.body (dom/getDocument)) (.domElement renderer))

14:19 benmoss: i believe `(.appendChild (.-body js/document) (.-domElement renderer))`

14:20 hellofunk: benmoss: thanks

14:34 timothyw: In test.check, I see generators like gen/keyword, gen/vector, etc.

14:34 But I don't see a generator for sets (gen/set)

14:35 Is there a preferred semantic for for generating sets?

14:37 lavokad: i'm gonna ask this again, just in a bit clearier way

14:37 I do lein new compojure-app testing. Then I go go routes/home.clj and add a function called home2 which prints "hello me". Then I change (GET "/" [] (home2)). Reload chrome, still hello world. I do to handler.clj, put a new line, save and now chrome refreshes with "hello me". Moreover, I go to back to home.clj and change (GET...) back to home. Chrome refreshes now with hello world.

14:42 gfredericks: timothyw: (gen/fmap set (gen/vector g)) isn't terrible

14:43 arrdem: timothyw: sets of what?

14:43 gfredericks: lavokad: did you save the first time?

14:43 timothyw: gfredericks: ah, what’s the ‘g in (gen/vector g)

14:43 lavokad: gfredericks: sure

14:44 timothyw: arrdem: well, in my case, a “group” can have a set of “users”

14:44 J_Arcane: FizzBuzz in a tweet (clojure): (map #(cond (= 0 (mod % 15)) "FizzBuzz" (= 0 (mod % 3)) "Fizz" (= 0 (mod % 5)) "Buzz" :else %) (range 1 100))

14:44 Any pointers on possibly shortening that further?

14:44 gfredericks: timothyw: your underlying generator; for the elements of the set

14:45 J_Arcane: are you golfing or wondering about idiomatic code?

14:45 timothyw: gfredericks: ah right

14:45 arrdem: timothyw: right. and users have some representation. my point is that a "keyword" is an actual set of atomic values where as a "set" is a distinct potentially ordered collection of arbitrary values. Consequently there is no baked in "set" generator because you want a set of _something_.

14:45 gfredericks: J_Arcane: I think condp could handle that

14:46 J_Arcane: gfredericks: Just new to the language and playing.

14:46 timothyw: arrdem: riiight, ok got that… then why’s “gen/vector” there?

14:46 J_Arcane: I'll look at condp.

14:47 arrdem: timothyw: because gen/vector is parametric on the set of things that can be in the vector. that's the 'g gfredericks used above.

14:47 gfredericks: arrdem: a hypothetical gen/set could work the same way

14:47 arrdem: gfredericks: sure I'm just trying to drive home why it would have to be generator parametric

14:48 * arrdem stops flogging the horse

14:48 gfredericks: I didn't think there was confusion about that

14:48 but I am trying to not listen to thomas the tank engine at the same time

14:49 noncom: anyone using ccw here? how does it work with java 8 and eclipse luna ?

14:50 timothyw: arrdem: ok, I think I’ve got it… I’m going to try the fmap approach

14:50 arrdem: timothyw: good luck!

14:50 timothyw: :)

14:50 tadni_: noncom: ccw being counterclockwise, the package for eclipse that bundles clj?

14:51 J_Arcane: gfredericks: Nice. Even shorter: (map #(condp = 0 (mod % 15) "FizzBuzz" (mod % 3) "Fizz" (mod % 5) "Buzz" %) (range 1 100))

14:51 noncom: tadni_: right

14:52 tadni_: noncom: I remember reading it works with Java 8, I'm not sure about different variants of Eclipse.

14:52 dbasch: J_Arcane: your :else could be anything truthy, e.g. 1

14:52 * tadni_ has used Eclipse in-general for maybe 15 minutes.

14:52 noncom: i see ...

14:55 J_Arcane: dbasch: I'm not sure what you mean. The result appears valid anyway.

14:55 gfredericks: J_Arcane: you should be able to include the mod logic in the predicate

14:55 ,(doc condp)

14:55 clojurebot: "([pred expr & clauses]); Takes a binary predicate, an expression, and a set of clauses. Each clause can take the form of either: test-expr result-expr test-expr :>> result-fn Note :>> is an ordinary keyword. For each clause, (pred test-expr expr) is evaluated. If it returns logical true, the clause is a match. If a binary clause matches, the result-expr is returned, if a ternary clause matches, i...

14:55 J_Arcane: gfredericks: That's the thought I had, but I've had trouble figure out how to simplify it.

14:56 dbasch: J_Arcane: I meant, for the version in which you were using cond, :else could be anything truthy (e.g. a digit or a symbol)

14:56 also, technically that’s not FizzBuzz because you’re not printing anything :)

14:56 gfredericks: (condp #(zero? (rem %2 %1)) n 15 "FizzBuzz" 5 ...)

14:56 J_Arcane: Heh, that's a fair point.

14:56 gfredericks: J_Arcane: ^

14:56 J_Arcane: Aha, yes. (didn't know about rem)

14:58 hyPiRion: #(case (mod % 15) 0 "FizzBuzz" (3 6 9 12) "Fizz" (5 10) "Buzz" %)

14:59 gfredericks: (inc hyPiRion)

14:59 lazybot: ⇒ 44

14:59 gfredericks: J_Arcane: ^ don't do that that's weird

15:00 J_Arcane: Heh heh,

15:01 hyPiRion: core match is also good for fizzbuzz

15:06 J_Arcane: Hmm. The (rem) solution actually winds up costing me one character, because I have to switch map's function from # to fn.: (map (fn [x] (condp #(= 0 (rem %2 %1)) x 15 "FizzBuzz" 3 "Fizz" 5 "Buzz" x)) (range 1 100))

15:11 hyPiRion: J_Arcane: flip the fn and #

15:12 #(condp (fn [x y] (= 0 (rem y x))) ..)

15:16 J_Arcane: Nope. Still 1-char longer. (map #(condp (fn [x y] (= 0 (rem y x))) % 15 "FizzBuzz" 3 "Fizz" 5 "Buzz" %) (range 1 100))

15:21 arrdem: Grimoire 0.3.6 incoming... bunch of basic maintenance fixes and a new static site build.

15:33 J_Arcane: Damn. there's a 77-char FB solution logged at anarchy golf. I wonder how they did it. By the time I get it to print I'm at 114.

15:39 dbasch: J_Arcane: here’s one in 80 http://clojurefun.wordpress.com/2012/09/21/code-golf-in-clojure/

15:41 gfredericks: ,mod%

15:41 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: mod% in this context, compiling:(NO_SOURCE_PATH:0:0)>

15:41 gfredericks: ,#(mod% 3)

15:41 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: mod% in this context, compiling:(NO_SOURCE_PATH:0:0)>

15:42 gfredericks: that can't work

15:42 ,(map #(let[t(mod% 3)z{0"Fizz"}]({0(str(z t)'Buzz)}(mod% 5)(z t%)))(range 1 101))

15:42 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: mod% in this context, compiling:(NO_SOURCE_PATH:0:0)>

15:42 gfredericks: ,(map #(let[t(mod % 3)z{0"Fizz"}]({0(str(z t)'Buzz)}(mod% 5)(z t %)))(range 1 101))

15:42 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: mod% in this context, compiling:(NO_SOURCE_PATH:0:0)>

15:42 gfredericks: ,(map #(let[t(mod % 3)z{0"Fizz"}]({0(str(z t)'Buzz)}(mod % 5)(z t %)))(range 1 101))

15:42 clojurebot: (1 2 "Fizz" 4 "Buzz" ...)

15:43 gfredericks: is there an older version of clojure where that parses as two symbols?

15:43 &(map #(let[t(mod% 3)z{0"Fizz"}]({0(str(z t)'Buzz)}(mod% 5)(z t%)))(range 1 101))

15:43 lazybot: ⇒ (1 2 "Fizz" 4 "Buzz" "Fizz" 7 8 "Fizz" "Buzz" 11 "Fizz" 13 14 "FizzBuzz" 16 17 "Fizz" 19 "Buzz" "Fizz" 22 23 "Fizz" "Buzz" 26 "Fizz" 28 29 "FizzBuzz" 31 32 "Fizz" 34 "Buzz" "Fizz" 37 38 "Fizz" "Buzz" 41 "Fizz" 43 44 "FizzBuzz" 46 47 "Fizz" 49 "Buzz" "Fizz" 52 53 "Fiz... https://www.refheap.com/89960

15:43 gfredericks: I guess so

15:43 &'#(mod% 3)

15:43 lazybot: ⇒ (fn* [p1__22095#] (mod p1__22095# 3))

15:43 gfredericks: &'#(mod%3)

15:43 lazybot: ⇒ (fn* [p1__22106# p2__22107# p3__22105#] (mod p3__22105#))

15:43 dbasch: gfredericks: prior to 1.5

15:44 J_Arcane: You can save some characters by ditching the map and doseq'ing over the sequence: (doseq[i(range 1 101)](println(#(condp = 0 (mod % 15) "FizzBuzz" (mod % 3) "Fizz" (mod % 5) "Buzz" %)i)))

15:44 But that's still 105, and I'm not sure much more space can be removed without it failing. (I found the issue with the mod% as well)

15:46 dbasch: ,(doseq[i(range 1 101)](println(#(condp = 0(mod % 15)"FizzBuzz"(mod % 3)"Fizz"(mod % 5)"Buzz"%)i)))

15:46 clojurebot: 1\n2\nFizz\n4\nBuzz\nFizz\n7\n8\nFizz\nBuzz\n11\nFizz\n13\n14\nFizzBuzz\n16\n17\nFizz\n19\nBuzz\nFizz\n22\n23\nFizz\nBuzz\n26\nFizz\n28\n29\nFizzBuzz\n31\n32\nFizz\n34\nBuzz\nFizz\n37\n38\nFizz\nBuzz\n41\nFizz\n43\n44\nFizzBuzz\n46\n47\nFizz\n49\nBuzz\nFizz\n52\n53\nFizz\nBuzz\n56\nFizz\n58\n59\nFizzBuzz\n61\n62\nFizz\n64\nBuzz\nFizz\n67\n68\nFizz\nBuzz\n71\nFizz\n73\n74\nFizzBuzz\n76\n77\nFizz\n7...

15:46 dbasch: J_Arcane: ^

15:48 J_Arcane: Ahh, yup, looks like I was too cautious.

15:48 That makes 98. :D

15:51 I think I'll break there, need sleep soon. thanks for the help.

16:40 SagiCZ1: hi guys.. is there a way to list all available methods i can call on a particular java object?

16:46 ,"am i here?"

16:46 clojurebot: "am i here?"

16:46 arrdem: #clojure is pretty quiet on sunday

16:48 SagiCZ1: arrdem: how come? is everyone in church?

16:49 mdeboard: Sunday is the day we rest from an arduous week of human and animal sacrifice

16:49 PeregrinePDX: Spending time with friends and family I would guess

16:49 mdeboard: or that

16:50 SagiCZ1: why are we here then

16:50 mearnsh: irc in church

16:51 SagiCZ1: hi-tech

16:58 mearnsh: dedication

17:00 mdeboard: irc is love

17:00 irc is life

17:02 danneu: sunday is my hammock time

17:04 mdeboard: rhickey would be proud

17:05 mearnsh: church of rhickey

17:05 mdeboard: Hammock-shriven Development

17:05 mearnsh: haha

17:05 mdeboard: I had to look up "shriven" to make sure I got the definition right

17:06 "hear the confession of, assign penance to, and absolve (someone)."

17:06 church-appropriate.

17:06 mearnsh: i had to look it up to double check i got the joke

17:06 mdeboard: lolol

17:10 * gfredericks is writing clojure code for generating SVG

17:16 gfredericks: huh.

17:16 format strings default to exactly 6 decimal places

17:26 * PeregrinePDX is writing clojure for finite capacity scheduling for a manufacturing erp I have thoughts about.

17:46 tadni_: "Instarepl" in Lighttable is pretty neat.

18:10 jeffterrell: Why does this work:

18:10 ,(meta (with-meta inc {:a 1}))

18:10 clojurebot: {:a 1}

18:10 jeffterrell: But this doesn't?

18:11 ,(meta ^{:a 1} inc)

18:11 clojurebot: nil

18:12 tadni_: I don't think I like Lighttable as much as Emacs, but I have a lot more of a liking than I intially thought I would.

18:14 jeffterrell: Read up on http://clojure.org/metadata to make sure I'm not missing something obvious, but it said both forms should be equivalent.

18:18 Bronsa: jeffterrell: the ^{:a 1} is putting the meta on the symbol inc

18:18 (with-meta inc {:a 1}) is putting the meta on the function

18:19 ,(def a 1)

18:19 clojurebot: #'sandbox/a

18:19 Bronsa: ,^:foo a

18:19 clojurebot: 1

18:19 Bronsa: ,(with-meta a {:foo 1})

18:19 clojurebot: #<ClassCastException java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.IObj>

18:19 Bronsa: jeffterrell: ^ is it more clear now?

18:20 * jeffterrell ponders

18:20 jeffterrell: I'm not sure how your examples help, but I get what you're saying about metadata being applied to the symbol rather than the function.

18:21 Bronsa: jeffterrell: so in the case of ^:foo x, the compiler will see the metadata -- in the case of (with-meta x {:foo true}) the compiler doesn't but the runtime value of x does

18:21 jeffterrell: That would explain the behavior, but it seems (a) like the reader macro is a pretty useless feature if that's true, and (b) at variance with the docs.

18:22 Bronsa: jeffterrell: that's neither the case :)

18:22 jeffterrell: Heh, that's good. :-)

18:22 OK, so you're saying it's a run-time vs. compile-time thing?

18:22 Bronsa: run-time vs read-time actually

18:22 jeffterrell: OK

18:22 * jeffterrell ponders some more

18:23 Bronsa: this is because the compiler "replaces" symbols with the value of the Var they're pointing at

18:23 ,(meta ^:foo [1])

18:23 clojurebot: {:foo true}

18:23 Bronsa: ,(meta (with-meta [1] {:foo true}))

18:23 clojurebot: {:foo true}

18:24 Bronsa: in case of collection literals, it "works" as you might expect it to work for symbols too

18:24 jeffterrell: Ah, because there's no var-lookup for collections. Interesting.

18:24 Hmm, what happens with a function literal?

18:24 ,(meta ^:foo #(+ 1 %))

18:24 clojurebot: {:foo true}

18:25 jeffterrell: Interesting. So it's really that symbols-pointing-to-vars are the special case here.

18:25 Bronsa: that's not a "feature" of function literals, it works for (fn [] ..) too

18:25 jeffterrell: That's surprising…to me at least. :-)

18:25 Sorry, I meant anonymous functions, not function literals.

18:25 Bronsa: fn and reify are documetned to propagate the read-time metadata to the run-time object they return

18:25 jeffterrell: Oh interesting.

18:26 Bronsa: well, reify is. fn I'm not sure but the implementation does it

18:26 jeffterrell: ,(meta ^:foo (fn [x] (+ 1 x)))

18:26 clojurebot: {:foo true}

18:26 Bronsa: ,(doc reify)

18:26 clojurebot: "([& opts+specs]); reify is a macro with the following structure: (reify options* specs*) Currently there are no options. Each spec consists of the protocol or interface name followed by zero or more method bodies: protocol-or-interface-or-Object (methodName [args+] body)* Methods should be supplied for all methods of the desired protocol(s) and interface(s). You can also define overrides for meth...

18:26 Bronsa: well

18:26 jeffterrell: ,(meta ^:foo inc)

18:26 clojurebot: nil

18:26 Bronsa: "reify always implements clojure.lang.IObj and transfers meta data of the form to the created object."

18:27 ^ that's from the docstring of reify

18:27 jeffterrell: OK, makes sense.

18:27 Bronsa: jeffterrell: the difference there is that the compiler knows at compile time that (fn []) and (reify) WILL be able to have metadata attached to them

18:27 while for a var, that's not the case

18:28 because var are dereferenced at runtime

18:28 vars*

18:29 jeffterrell: Hmm, it's still not quite clicking for me, but maybe this question will help me understand.

18:30 How would I access the metadata if I say `^:foo inc`? You said it's attached to the symbol inc? Can I access the `{:foo true}` map somehow?

18:30 Bronsa: jeffterrell: you can't access it

18:30 the compiler has it at compile time

18:30 but at runtime it doesn't exist

18:30 you can access it via a macro though

18:30 ,(defmacro x [y] (list 'quote (meta y)))

18:30 clojurebot: #'sandbox/x

18:30 Bronsa: ,(x ^:foo inc)

18:30 clojurebot: {:foo true}

18:32 jeffterrell: Ahh, OK, I think I got it. The compiler sees all the metadata that is attached via the ^ reader macro form. Then it passes it on to the actual object (available at run time) in certain situations. But the symbol-referencing-a-named-fn case is not one of those situations.

18:32 Is that about right?

18:32 Bronsa: jeffterrell: yes

18:32 jeffterrell: Is that the significance of this error message:

18:32 ,(meta ^:foo "s")

18:32 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: Metadata can only be applied to IMetas>

18:33 Bronsa: no

18:33 jeffterrell: metadata can only be applied to some clojure objects

18:33 those objects whose class implements the interface clojure.lang.IMeta

18:33 jeffterrell: Ah, OK, that makes sense.

18:34 Bronsa: you can attach metadata to: the clojure collections, the clojure referenec types, reify, functions and defrecords

18:34 you can't attach metadata to strings & keywords for instance

18:34 jeffterrell: Hmm, alright. Good to know.

18:35 Bronsa: even though keywords are clojure objects, they are interned so metadata wouldn't make any sense

18:35 jeffterrell: Thanks a lot for explaining, Bronsa. That is super helpful!

18:35 Let's see if this works:

18:35 (karma Bronsa)

18:36 Bronsa: jeffterrell: it's (inc username) :)

18:36 jeffterrell: (inc Bronsa)

18:36 lazybot: ⇒ 48

18:36 jeffterrell: Sweet!

18:44 hyPiRion: it's

18:44 (identity Bronsa)

18:44 lazybot: Bronsa has karma 48.

18:48 jeffterrell: Weird, I would think that would return 'Bronsa :-)

18:49 Bronsa: Oh, one other question, what did you mean, "the Clojure reference types"?

18:50 I'm guessing that either means things like refs and atoms (because they refer to something and can be deref'd) or else the basic types like int, float, etc.

18:52 Bronsa: jeffterrell: yeah ref, atoms, agents, vars etc

18:52 jeffterrell: OK, makes sense, thanks.

19:24 augustl: just did (defn my-fn [{:keys test}] ...) and got the error "java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol". The error is obvious, but the error message is pretty bad, and it's not the first time Clojure doesn't yield readable errors

19:24 does the clojure compiler have suboptimal error handling for performance reasons?

19:24 or is it just that nobody has cared to improve it yet?

19:25 is it perhaps one of the biggest challenges of functional programming - in order to handle errors well, you need to manage and pass around a "context" all the time everywhere? :)

19:26 hyPiRion: augustl: see https://www.youtube.com/watch?v=o75g9ZRoLaw on improved error messages from macros

19:26 justin_smith: augustl: my take is that we just don't make much use of validation

19:31 augustl: the error in question is probably that way because way down in a function somewhere a seq is being created, and at that point there is no information about which line number, file etc the error occurred in

19:31 hyPiRion: saved for later, have to be silent right now :)

19:32 hyPiRion: Me too :) I should in theory be in bed as well

19:35 augustl: hyPiRion: seems like this particular instance was macro related, btw

19:35 the error has a nice line number in it, but it's the line where the macro is invoked :)

19:38 cbarrett: I'm coming from a Scheme background -- why does clojure have keywords? What's the advantage of :foo over 'foo?

19:39 beamso: ,(:foo {:foo "bar"})

19:39 clojurebot: "bar"

19:39 hyPiRion: ,('foo {'foo "bar"})

19:39 clojurebot: "bar"

19:39 llasram: cbarrett: Clojure symbols can carry metadata, which means two symbols can be equal but not reference-identical and have different metadata

19:39 cbarrett: When is that useful?

19:39 llasram: cbarrett: Whereas equal keywords are also guaranteed to be reference-identical

19:40 cbarrett: I'm sure there's a reason for all this, just trying to understand

19:41 llasram: cbarrett: Clojure uses metadata in a variety of ways, but metadata on symbols is used most commonly to communicate type information to the compiler or to macros

19:41 cbarrett: What sort of type information do symbols carry? Don't they evaluate to themselves?

19:42 hyPiRion: cbarrett: what I found as more important is that keywords evaluate to themselves.

19:42 cbarrett: for example

19:43 ,(let [x (with-meta 'foo {:lineno 10, :column 8})] (meta x))

19:43 clojurebot: {:column 8, :lineno 10}

19:43 hyPiRion: Could, in theory, be used to give better error messages

19:44 llasram: cbarrett: Or for a type example:

19:45 (fn [^String s] (.index s "\n"))

19:45 cbarrett: Hmm.

19:45 I'm not really following.

19:46 It seems like kind of a wart...

19:46 llasram: The ^String is metadata syntax, shorthard actually for ^{:tag String}

19:46 That communicates to the compiler that `s` is of JVM type `String`, which allows it to emit code which directly invokes the `.index` method vs using (much slower) runtime refelction

19:48 cbarrett: I'm very new to Clojure so I feel like I'm missing something or it's a taste / style thing

19:48 But it just seems like pushing implementating details into the user's lap

19:48 Like the loop / recur thing (which I understand is needed given the nature of the JVM etc)

19:49 Not trying to criticize, just trying to figure out where the gap is.

19:50 llasram: cbarrett: I think there's some of that (pushing implementation details)

19:51 Clojure symbols support metadata (along with most Clojure data structures) which prevents equality from being identical with reference identity

19:51 cbarrett: My background is Scheme (and Haskell) so

19:51 llasram: The latter is a useful property, so Clojure has a separate type with that property, which also happens to have the additional useful property of `eval`ing to itself

19:52 cbarrett: Hm.

19:52 So symbols aren't atoms then?

19:53 In the general sense of that temr

19:53 llasram: The atom vs not distinction isn't as clear on Clojure

19:53 cbarrett: *term

19:53 I don't know the clojure definition of it

19:53 The general sense being an inlined string ensuring pointer quality and value equality are isomorphic

19:53 arrdem: In Clojure an "atom" is a distinct atomic reference type. It's not used to describe whether a value can somehow be traversed or partitioned as in other lisps.

19:54 cbarrett: yeah I didn't know about that

19:54 llasram: cbarrett: Symbols are (Scheme-wise) atoms in the sense that they aren't collections, but like I said before -- they don't have the pointer=value equality property

19:54 cbarrett: hm

19:54 OK

19:54 Seems weird but

19:55 Recovering the property of pointer equality being a proxy for value equality seems useful.

19:55 llasram: cbarrett: Exactly, and that's what keywords provide

19:55 cbarrett: Don't quite undertsand why that property was lost in the first place

19:56 llasram: cbarrett: AFAICT, because rhickey decided that it would be useful for symbols to carry metadata

19:56 This appears to be going a bit circular

19:56 cbarrett: No that's a good explanation

19:56 Thank you

19:56 arrdem: Clojure: Rich made a design decision and the rest of us choose to live with it

19:57 cbarrett: That's perfectly fine

19:57 Trying to understand those design decisions & build intuition

19:59 hyPiRion: cbarrett: I agree that recur is also an implementation detail pushed onto the users, but I've found it somewhat helpful actually. In Scheme or Haskell, I can't immediately see whether a function is tail-recursive or not when it calls itself, but I do in Clojure.

19:59 cbarrett: hyPiRion: explicit recursion is the goto of functional programming

19:59 morphisms being the structured programming alternative.

20:02 hyPiRion: well, at times I've had to implement things which doesn't overflow the stack. At that point it's reassuring to know that the function is tail recursive.

20:03 justin_smith: cbarrett: morphism as in "If f is a morphism with source object A and target object B, we write f : A ⤇ B."?

20:03 hyPiRion: Consider the difference between stric and lazy fold in Haskell, for instance.

20:03 cbarrett: Yeah

20:03 There's a whole library of these things

20:03 with scary sounding greek names but they're just patterns

20:03 You've probably implemeneted e.g. paramorphisms before

20:05 Many of these structured recursion patterns can be transformed an interative comuptation or can be written to use a side-channel stack rather than the language's call stack.

20:05 justin_smith: cbarrett: scala isn't very popular around these parts in general, but from what I've seen that kind of approach is much more compatible with scala than clojure

20:05 cbarrett: Never written any Scala

20:05 My introduction to this stuff was thru Haskell and category theory.

20:06 Was looking at doing source transformation using them and then trying to make assertions about whether two transformations composed cleanly, etc.

20:07 Reducers and transducers seem like they'd fit well into such an algebraic formalism.

20:07 justin_smith: not to say you cannot do ct informed clojure, but it'll be a fight, and an odd fit. There are lens and monad libraries, but they don't get used much, because they are complex to use, harder to use than standard clojure, and perform poorly.

20:08 cbarrett: Sure, I'm not trying to

20:08 just that's the intuition I hve.

20:08 justin_smith: got it

20:10 cbarrett: we have functions like map, iterate, and reduce, which are almost always preferable to a raw recursion scenario

20:10 but on the odd instance recur is clearer

20:11 cbarrett: justin_smith: indeed. these morphisms I mentioned are just generalized versions of those that work on any structure, not just lists / sequences (e.g. trees)

20:11 same intuition

20:11 just with more types ;)

20:15 BAMbanda: Does anyone have a hack for the clojure repl? Can we get command history and syntax highlighting without being in emacs and without rlwrap?

20:15 Also I prefer the actual clojure jar instead of the lein repl ...

20:15 justin_smith: BAMbanda: nrepl supports middleware, so it's at least possible

20:15 oh, well nrepl is the lein repl, so good luck

20:16 nrepl will be easier to extend than the one built in

20:16 BAMbanda: hmm, I have the latest lein, and haven't done anything to profiles.clj and get weird error messages

20:16 justin_smith, let me show you a pastie

20:17 justin_smith: feel free to share

20:17 BAMbanda: http://pastie.org/9534957

20:18 justin_smith: looks like 2.4.3

20:18 (lein 2.4.3 that is)

20:19 try "lein upgrade 2.4.2"

20:19 BAMbanda: hmm, let me try

20:19 justin_smith: the error goes away if you run lein inside a project directory

20:19 the lein team did not catch the error, because they only run lein repl inside projects

20:20 BAMbanda: interesting, whatever happened to the idea of exploratory hacking diaries

20:20 justin_smith: BAMbanda: dunno - I use projectless repls all the time, but it's uncommon among more experienced clojure devs for some reason

20:21 BAMbanda: justin_smith, perfect it workds now. Do you accept bitcoins>

20:21 ?

20:22 justin_smith: no, thanks anyway though

20:22 BAMbanda: sure

20:22 arrdem: (inc justin_smith) ;; they're both internet points

20:22 lazybot: ⇒ 74

20:23 BAMbanda: (inc justin_smith)

20:23 lazybot: ⇒ 75

20:23 BAMbanda: :)

20:24 (def justin_smith (* justin_smith justin_smith))

20:24 justin_smith: heh

20:24 arrdem: if only I could trade in #clojure karma for drugs

20:24 arrdem: justin_smith: STARTUP IDEA GOGOGOGO

20:24 BAMbanda: too bad the ram will clear and your outta luck

20:25 justin_smith: BAMbanda: clojurebot uses a db of some sort

20:25 BAMbanda: hmmmm, time to hackk

20:25 arrdem: justin_smith: mongo. if the ram clears no karma :P

20:25 justin_smith: heh, got it

20:29 jeffterrell: BAMbanda: As far as command history goes, the regular `lein repl` should support the standard readline bindings out of the box, e.g. ^P and ^N.

20:29 Can't help you with syntax highlighting. That would be cool though.

20:30 justin_smith: jeffterrell: well, one of his requirements was that he doesn't want to use lein repl

20:31 jeffterrell: Heh, fair enough.

20:31 Missed that part.

20:33 BAMbanda: nahh, its fine now. I just had a lot of trouble with lein for a while, java specifically (security certificate/maven issues)

20:34 Ruby has a project called pry, that replaces its standard "repl" called irb and it is jammmmmmm_packed with features

20:34 justin_smith: BAMbanda: yeah, there has been some weirdness with the latest lein release

20:34 BAMbanda: The ability to launch default editors to edit source, syntax highlighting, plugins, and a bunch of stuff.

20:34 lein carries the same potential

20:35 but has the advantage of the lisp tradition that arguabaly gave birth to repl style coding. So I was hoping to see some more. Maybe I should contribute syntax highlighting

20:35 justin_smith: middleware are our version of plugins

20:35 BAMbanda: yeah i should check it out

20:35 justin_smith: a middleware to syntax hightlight makes sense

20:36 there was once talk of middleware for arbitrary mime types

20:36 so that a repl inside a browser for example could display non-textual data in a natural format

20:36 arrdem: we need a native clojure syntax highlighter anyway...

20:36 jeffterrell: Agreed: syntax highlighting middleware sounds pretty spiffy.

20:37 justin_smith: BAMbanda: have you looked at gorilla?

20:37 BAMbanda: no, let me check it out right now

20:38 the mime repl idea sounds sickk

20:38 justin_smith: http://gorilla-repl.org/

20:38 gorilla gets close to some of that

20:38 BAMbanda: sweeeet

20:40 catern: sigh

20:40 all these things would be nice

20:40 if they had nice keyboard shortcuts and buffers and everything

20:40 basically, if they were inside emacs

20:40 rather than a browser

20:40 literate org-mode clojure programming?

20:41 justin_smith: catern: that does work, without the things like built in plotting of course

20:41 catern: though if your code outputs an svg, emacs could display that

20:41 BAMbanda: gorilla kind of reminds me of wolfram language style coding

20:41 cbarrett: looks a lot like IPython as well

20:41 BAMbanda: plots, graphs, 3d geometrial objects...etc

20:41 catern: i wish they worked better, i wish emacs webkit integration was finished already

20:41 justin_smith: BAMbanda: yeah, I think that those the influences

20:42 arrdem: catern: oh that's actually happening? I thought it was a joke

20:42 BAMbanda: very powerful stuff, its exciting to be a developer these days

20:42 imagine back in the day, low level memory management, no glitter

20:42 justin_smith: arrdem: catern: cutting edge emacs features wallow in poes law like pigs in mud

20:42 BAMbanda: woah, i just read emacs webkit integration

20:42 sounds serious

20:42 arrdem: BAMbanda: someone doesn't write os and below software....

20:43 gfredericks: if I type "emacs vim integration" will it suddenly be a real thing too?

20:43 cbarrett: gfredericks: there's actually a pretty good vim mode for emacs.

20:43 arrdem: gfredericks: lol evil-mode get wrekt

20:43 catern: arrdem: well someone's doing it...

20:43 gfredericks: nah I'm imagining you have vim running in the background for some reason

20:43 catern: gfredericks: that's why i want this to be inside emacs, so i can use vim keybindings...

20:44 BAMbanda: i definitely admire and respect the kernel guys, without them we'd be nothing

20:44 catern: gfredericks: what, you want it to be inside vim? or someone to reimplement vim yet again, very poorly?

20:44 gfredericks: M-x eclipse-mode

20:44 cbarrett: catern: lol

20:44 justin_smith: gfredericks: awesome

20:44 BAMbanda: but we are able to be more fluid in our usage of language as expression

20:44 gfrederikcs: M-x komodo-mode

20:44 arrdem: gfredericks: when you really want to make sure that you don't have any ram left...

20:45 BAMbanda: arrdem, bare-metal scalable hypervisors in the cloud

20:45 I heard it from a clojurepodast from cognitec, things are happening

20:46 http://blog.cognitect.com/cognicast/?tag=podcast

20:46 catern: arrdem: well it isn't an official feature or anything, it just would be nice and add to emacs' already insane level of power

20:48 arrdem: Grimoire 0.3.7 dropping in a minute...

20:48 looooots of cleanups

22:06 jamesnvc: Hi! I’m seeing some very confusing issues when compiling clojurescript at runtime, where (= :method (keyword “method”)) is false

22:07 TEttinger: ,(= :method (keyword "method"))

22:07 clojurebot: true

22:07 jamesnvc: Things work under :simple optimizations, but then die under :advanced, seemingly because variables that are supposed to be bound by destructuring a map with {:keys […]} are nil

22:07 TEttinger: hm

22:08 jamesnvc: I’m not sure if that’s what’s causing the problem, but it is very confusing

22:08 TEttinger: I would be confused too... I don't use cljs so I can't be of much help

22:08 jamesnvc: I’ve been seeing issues about strange things happening with keywords hashing, I guess this is part of it

22:09 dammable difficult to get a minimally-reproducable test case though

22:18 justin_smith: jamesnvc: on the online cljs fiddle I can't reproduce that http://cljsfiddle.net/

22:18 jamesnvc: yeah, I can’t reproduce it out side of my app either

22:19 hiredman: jamesnvc: clojurescript has it;s own keyword equality predicate that is not =

22:19 I forget what it is called

22:19 jamesnvc: oh?

22:19 Bronsa: keyword-identical?

22:20 hiredman: I belive = works fine though

22:20 jamesnvc: I remember seeing that identical? doesn’t work on keywords, but I thought = did

22:20 yeah

22:20 hiredman: oh

22:20 maybe I am misrembering

22:20 Bronsa: jamesnvc: which version of cljs are you using?

22:21 hiredman: but a runtime created keyword not comparing as equal to a compile time constant keyword seems like exaclty that issue

22:21 jamesnvc: that aside though, the actual problem seems to be that destructiing a map isn’t working

22:21 Bronsa: 0.0-2322 now, was seeing the same on 2277

22:22 Bronsa: jamesnvc: ah, dunno then

22:22 jamesnvc: hiredman: yeah, I figure it must be something like that — I’m only seeing the issue when I’m doing some kinda crazy run-time invocations of the clojurescript compiler

22:26 for some reason, literal keywords are also being output as undefined in javascript

22:26 I guess that’s why they aren’t equal :/

22:27 justin_smith: that's fucked up

22:27 hiredman: jamesnvc: are you incrementally compiling clojurescript?

22:28 jamesnvc: hiredman: no, it wipes everything between compiles

22:29 hiredman: jamesnvc: the clojurescript compiler generates what is basically a global constant table of keywords, if you are incrementally compiling and running bits of clojurescript, you might be overwriting that global table of keywords with a different table with different keywords

22:29 jamesnvc: hiredman: hmm, that sounds promising

22:29 yeah, constants_table.js is empty

22:30 that doesn’t seem right

22:37 Any idea as to why constants_table.js would be completely empty?

22:45 * tadni_` just donated to SICP Distilled. https://www.kickstarter.com/projects/1751759988/sicp-distilled

22:47 danielcompton: tadni_`: same, it looks pretty cool

22:50 tadni_: danielcompton: I wonder if it will spark interest into this, http://sicpinclojure.com/, project.

22:51 This has actually been one of the motivating factors leaning me to Clojure over other Lisps.

22:51 danielcompton: tadni_: I saw it as sicpinclojure that would get finished

22:52 tadni_: danielcompton: Well, SICP Distilled mentioned it will translate the examples, but I don't think he was planning on putting them into a text outside of his helper text/site.

22:52 danielcompton: right.

22:53 tadni_: danielcompton: I mean, if most of the leg work is already done -- it'd be trivial to use/copy it in sicpinclojure.com .... assuming that's legal.

23:08 ddellacosta: so, I've been a loser and not updated lein in a long time, then I finally did, and now it seems like tab completion isn't working for me. what did I do wrong, or did I miss some information at some point?

23:09 justin_smith: ddellacosta: in a lein repl in a terminal?

23:09 ddellacosta: yeah

23:09 justin_smith: and I just noticed the message "Unable to initialize completions."

23:09 justin_smith: well, there you go :) - dunno what makes that happen though - is this related to a plugin in your profiles.clj?

23:10 ddellacosta: justin_smith: huh, that's a good guess, let me try disabling everything there to see

23:11 justin_smith: nope, still the same. hrm.

23:12 hmm, looks like maybe this has to do with reply and clojure-complete, which makes sense

23:13 justin_smith: that's a separate plugin, right?

23:14 ddellacosta: justin_smith: is it a plugin?

23:15 justin_smith: oh, I guess not

23:15 ddellacosta: justin_smith: I've noticed that when I start lein it is complaining about not finding that--but the thing it, it was always complaining about not finding that to the extent that I had started ignoring it, and only now does it actually seem to matter

23:16 justin_smith: odd

23:16 ddellacosta: yeah, I have to poke around a bit more

23:16 maybe I can just install that

23:16 alright, well, thanks justin_smith!

23:21 yeah, simply including clojure-complete in my project.clj did it, but kind of annoyed that I had to do that...seems like it should get picked up if it is a basic lein (via repl-y) dependency?

23:23 justin_smith: the idea may be to make the completion middleware modular, so people can use the one they prefer? maybe this is related to editor tooling

23:24 arrdem: AFAIK cider completion is already REPL independent middleware

23:25 technomancy: ddellacosta: are you using lein master?

23:25 * tadni_ still has aboslutely no idea what the word/name leiningen is from/refering to/is a reference of/et.

23:25 ddellacosta: technomancy: um, this is just the latest update, one sec

23:26 technomancy: 2.4.3, just from doing an upgrade yesterday

23:27 technomancy: ddellacosta: oh, no idea then; sorry

23:27 danielcompton: tadni_: it's from a short story Leiningen vs The Ants

23:27 $google Leiningen vs the ants

23:27 lazybot: [Leiningen versus the Ants--Carl Stephenson (1893-1954)] http://www.classicshorts.com/stories/lvta.html

23:27 ddellacosta: tadni_: read the top of the README here: https://github.com/technomancy/leiningen

23:27 tadni_: danielcompton: Oh wow, no fooling?

23:27 danielcompton: tadni: and Ant is a Java build tool

23:27 tadni_: Ah.

23:27 ddellacosta: technomancy: no worries. Who knows what kind of arcane old settings I've got hanging around here. :-(

23:28 abaranosky: what do I need to do to get my patch into Clojure? I've got it on JIRA, and started a thread on the clojure-dev mailing list. Do I now just wait for the clojure.core team to give it a yay or a nay? Or do I need to actively try to drum-up some support for the patch?

23:28 technomancy: ddellacosta: for the record, `lein downgrade $OLD_VERSION` is a thing too

23:28 abaranosky: I recommend generous bribery

23:28 abaranosky: ha

23:28 maybe I should fork Clojure ;)

23:28 technomancy: you could also hire a professional thief to pilfer the SSH private keys and passphrase of a core member

23:28 ddellacosta: technomancy: gotcha, will consider that

23:29 justin_smith: technomancy: lein upgrade $OLD_VERSION works too, and sends the stern message that you are switching because the old version is better

23:29 technomancy: justin_smith: lifehack: `lein "upgrade" $NEW_VERSION` also works, but sadly the shell strips the sarcasm before Leiningen can detect it

23:30 justin_smith: lol

23:30 ddellacosta: can't you also do lein upgrade "$NEW_VERSION" ?

23:30 technomancy: yeah

23:30 ddellacosta: for minor bug fix releases

23:30 technomancy: for whatever

23:30 ddellacosta: sorry, maybe I'm projecting

23:31 * ddellacosta was trying to make a joke about sarcastic quotes in commands, but failed

23:31 ddellacosta: lein upgrade $DDELLACOSTA_HUMOR_CONST

23:38 danielcompton: $DDELLACOSTA_HUMOR_CONST is already up-to-date.

23:38 ddellacosta: danielcompton: I think that's a burn somehow

23:39 danielcompton: but the $DDELLACOSTA_HUMOR_CONST settings aren't sufficient for me grasp it

23:39 setting rather

23:43 danielcompton: How does one give clojure apps a more useful name in jps than 'core'?

23:47 arrdem: technomancy: how do dependency scopes interact with profiles? reading the maven documentation they seem redundant.

23:48 L8D: Where should I start if I want to replace my existing node.js express REST API with Clojure?

23:49 And replace my client-side React app with ClojureScript's om?

23:51 hipitihop: I have a large vector of maps, about 30k and I need to detect duplicates based on extracting multiple keywords from each map e.g. using (juxt :w :r :s :t) I have tried with group-by and frequencies, eliminating the juxt, all are too slow, e.g. I'm getting 55-60 seconds so I need to rethink the approach altogether. anyone have ideas for alternate algo ?

23:53 arrdem: hipitihop: do you need to count duplicates? a chunked map/reduce merging on values with + could work...

23:54 justin_smith: hipitihop: what about using select-keys?

23:54 hipitihop: never mind, that won't actually be faster than comparing juxt results

23:55 danielcompton: hipitihop: do you need to detect duplicates or just remove them?

23:55 hipitihop: arrdem, ideally counted but not important, as long as I know which combination of keys has > 1

23:55 danielcompton, just detecting which ones are

23:55 arrdem: hipitihop: can you show a small I/O case? http://refheap.com

23:56 anyone know if there's a standard URI encoding for Maven dependencies?

23:56 danielcompton: hipitihop: what's the distribution like? Are they mostly unique or mostly mixed?

23:56 hipitihop: danielcompton, mostly unique, so duplicates are an edge case

23:57 justin_smith: hipitihop: another question, where are the maps being generated? there is likely a more efficient possibility at the site of map creation (or the site of loading the maps from their source)

23:58 and now that I think of it, lazily comparing the keys one at a time (bailing at first non-match) could be faster than running juxt then checking equality

23:58 danielcompton: hipitihop: I did this a while ago and used java.util.TreeMap

23:58 https://gist.github.com/danielcompton/4b1a59054a40a89c19ec

23:59 I saw a 5x speedup but my sample size was much smaller than yours

23:59 hipitihop: or it's at least similar

23:59 hipitihop: justin_smith, maps are generated from a prior xml parsing step which creates a vector of maps each map represents an element in original xml i.e. keywords in resulting map correspond to attributes in each element

23:59 danielcompton: arrdem: from my coworker talios: "not in any official standard I don't think - the general one most people use is mvn:grouopId/artifactId/version/extension/classifer"

23:59 arrdem: :i.e. mvn:org.apache.felix.karaf/apache-felix-karaf/1.4.0/xml/features:

Logging service provided by n01se.net