Fork me on GitHub
#clojurescript
<
2015-11-27
>
mudphone00:11:01

Yeah, I really like the SICP material. It’s been quite inspiring to read through it (I’m not quite done though).

mudphone00:11:56

oh cool, I’m going to have to watch her video on Adapting Clojure to a CS Classroom.

jaen00:11:40

Another nice book is How to Design Programs of Racket fame.

mudphone00:11:49

oh, one of the Realm of Racket authors, thanks… will check it out

kauko08:11:17

Are there any clojurescript libraries that use vdom and web workers in a way that the UI thread is only given the smallest possible patch, and nothing else is done in the UI thread?

kauko08:11:08

If I understand correctly, this is something that will be in Angular 2

jaen09:11:20

Wow, this Pokedex is so swell _

kauko09:11:19

That blog post really is a pretty good example of why the browser is such a terrible platform for development. It’s 2015 and people are excited for multithread, using technology that’s been around for 5 years (?), but has hardly been adopted because of lacking browser support - .-

kauko09:11:50

Mind you, I’m not saying we should not dev for the browser, rather than this is just one of of those things that’s kind of funny and sad at the same time

tragiclifestories09:11:50

It’s not a terrible platform, it’s just several OK-ish ones which are almost compatible, which is somehow worse

thheller09:11:35

webworkers are pretty cool actually, only problem is that there is no efficient way to share data between them and the page

thheller09:11:23

so you can end up in scenarios where serializing/deserializing stuff actually takes longer than the actual computation

thheller09:11:40

but transit makes that much less of the problem than edn

thheller09:11:16

does react have the ability to split the diff/patch/apply? that would be interesting

jaen09:11:45

Hmm, but there's transferable objects as well to use shared memory instead of copying, and it says you can transfer MessagePorts. This could probably serve to make it faster.

thheller09:11:42

doesn't work for cljs types though

thheller09:11:24

but the whole webworker thing falls apart as soon as you need anything from the dom anyways

thheller09:11:33

eg. the position/height of a dom element

jaen09:11:03

Yeah, that's true, but being able to run logic there still looks like it could work sensibly

thheller09:11:44

yeah but it is kind of all or nothing for most apps

thheller09:11:34

since the big atom architecture doesn't work so well if you need to split it

thheller09:11:18

you can do it for a bunch of stuff though, just not UI related

jaen09:11:37

But is a split along application logic / view logic really that bad of an idea?

jaen09:11:44

Well, yeah, that's how I imagined would work

jaen09:11:54

UI in the main thread, logic in a worker

thheller09:11:21

there usually isn't much logic going on though

thheller09:11:45

I mean if you really to expensive calculations in the client use webworker

thheller09:11:56

but all of that happens on the server in my apps

thheller09:11:11

the most expensive stuff usually is the react diff

thheller09:11:15

or parsing response data from the server 😛

jaen09:11:18

Fair point, I suppose

thheller09:11:59

but as the pokedex stuff shows

thheller09:11:09

you can get pretty far with totally different techniques

thheller09:11:42

and OMG is javascript terrible 😛

thheller09:11:27

this exports/require stuff is terrible

thheller09:11:58

have they not heard of the closure compiler .. it is so much better

thheller09:11:19

every time I look through a js project I appreciate CLJS so much more

tragiclifestories10:11:17

ehh, it’s not so bad. I make my cash dollars from JS, and it’s a more fun and expressive language to work in than many. There are warts, but with a bit of practice you can code around them. Not sure what your problem with the require stuff is; I like that it’s just an expression, so it’s immediately clear what scope you’re using a package in, although that’s going away with ES6 imports

tragiclifestories10:11:50

And only now with CLJS and elm and friends are we getting really workable options for compile-to-JS languages with radically different semantics

thheller10:11:38

the issue I have with it is the code structure it produces

thheller10:11:42

one file per function basically

thheller10:11:01

I mean come on .. that is overkill

thheller10:11:07

next up is one package per function

thheller10:11:23

just put em all in one file

thheller10:11:38

and let the compiler figure out which aren't used 😛

thheller10:11:19

seriously ...

tragiclifestories10:11:44

It’s a fair point - the benefit you get from closure is the dead code analysis, which is exceptionally good

tragiclifestories10:11:58

require/commonjs stuff works better on the node side, in the browser it’s a somewhat leaky abstraction which gets you the warm glow of familiarity, plus everything on NPM that makes sense in a browser simple_smile

jaen10:11:35

Well, normal libraries don't look like that, I think. Take a look at react for example - it has a more sane module structure; they build up a module object and export that.

tragiclifestories10:11:57

it depends what you mean by normal

thheller10:11:13

react does that as well, the functions are just longer and sometimes have "some" support functions

tragiclifestories10:11:26

look at lodash nowadays, you have the standard package with all the functions, but there’s also a NPM entry for each individual function

jaen10:11:27

Ok, that's anecdotal - that is, it's the first library with such granularity I've seen.

thheller10:11:33

but not that extreme yes

thheller10:11:56

d3 recently moved to this style as well

thheller10:11:30

one freaking project per "function" 😛

jaen10:11:33

But what drives that then exactly?

tragiclifestories10:11:34

it’s partly philosophical (there’s an ideologically commitment to Tiny Things in node) but partly due to the dumbness of compilers, as discussed

tragiclifestories10:11:00

ie, you don’t want 30k of lodash just for _.compact

thheller10:11:14

they can't do what closure does ... if you include a file you keep everything in it

thheller10:11:23

regardless of whether you use it or not

thheller10:11:37

so you want every file to be as small as possible

jaen10:11:51

Well the philosophical part is taken to the extreme, but ok, I get the "can't shake them trees" part.

jaen10:11:13

But well, wouldn't a better solution be to figure out how to tree shake stuff instead.

jaen10:11:22

Instead of go full ideololo?

thheller10:11:29

granted writing closure js by hand is not fun either

tragiclifestories10:11:35

but for the time being, we have stuff like this https://www.npmjs.com/package/methods

tragiclifestories10:11:49

exactly what it says on the tin (tm)

tragiclifestories10:11:13

module.exports = [
    'get',
    'post',
    'put',
    'head',
    'delete',
    'options',
    'trace',
    'copy',
    'lock',
    'mkcol',
    'move',
    'purge',
    'propfind',
    'proppatch',
    'unlock',
    'report',
    'mkactivity',
    'checkout',
    'merge',
    'm-search',
    'notify',
    'subscribe',
    'unsubscribe',
    'patch',
    'search',
    'connect'
  ];

jaen10:11:46

wait, what

jaen10:11:55

the whole package is just an array of string constants?

jaen10:11:01

That's crayzay '

tragiclifestories10:11:02

it’s a transitive dependency of some important packages, you can see there

thheller10:11:31

yeah js has some crazy code

tragiclifestories10:11:41

well, in fairness, that list would only be written once in your application, so why should it be written more than once in the entire world? 😉

jaen10:11:55

But I don't get

trancehime10:11:04

I'm quite new to CLJ+CLJS development, and I've kind of run into a wall with regards to thought process

tragiclifestories10:11:32

@trancehime: what problems you running into?

jaen10:11:43

@tragiclifestories: You can require single files with require, so why separate packages?

trancehime10:11:44

@tragiclifestories: I'm stuck with trying to figure out a sane way to implement WebSockets using sente on immutant in order to create a sort of lobby system where I can keep track of users subscribed to a particular lobby

tragiclifestories10:11:07

where would it go? I mean, you could put it in node stdlib somewhere, but what if I want a list of HTTP methods on the client with browserify/webpack etc

tragiclifestories10:11:26

very few people require this directly, it’s just buried in express, request etc

trancehime10:11:37

I mean, the actual implementation part shouldn't be that difficult, but it's the whole logic and architecture behind it really

tragiclifestories10:11:39

@trancehime: I’ve never worked with websockets so it’s a bit tough for me to go into specifics, but there’s some ideas floating around for the architecture stuff

jaen10:11:57

@trancehime: how comfortable are you with Clojure? Because I have code for a presentation that does something really close to that (a chat with channels, but at the moment no join/part) I could link to

jaen10:11:18

And then answer questions if it's unclear (which it probably will be, I'm not the greatest programmer ever)

trancehime10:11:31

@jaen Any references would be nice; I've pretty much been forced into using Clojure due to a work assignment/project, and deadline is real tight. I've already done and insane amount with the time I've been given, despite having only had about a few days of time allotted to refresh myself on it. So I'd say I

trancehime10:11:37

I'm fairly comfortable with it by now

tragiclifestories10:11:40

you could have a look at this, another one of those post-flux/FRP ideas, should be nice and agnostic as to where your data is coming from https://github.com/Day8/re-frame

trancehime10:11:07

Yeah, I've actually read the re-frame README, a very interesting read. Unfortunately it's assuming your data is within the client-side using something like datascript

tragiclifestories10:11:20

forgot about that bit

trancehime10:11:34

I've managed to populate my data with AJAX calls and present it in Reagent, so that's not a real problem

trancehime10:11:48

er, rather my atoms

trancehime10:11:15

And not to mention, I have to handle email notifications too, and postal on the CLJ side really hasn't been helpful

trancehime10:11:36

At this point work is making me do full-stack all on my own in a language I've only just become comfortable in using haha

trancehime10:11:58

@jaen thank you so much, I appreciate it

jaen10:11:00

presentation.backend.async.core is the backend, presentation.backend.async.core is the frontend part of the async communications

jaen10:11:46

presentation.backend.chat.core is next-to-none backend logic, presentation.frontend.chat.core is the chat reagent component

jaen10:11:16

Now it's more complicated than strictly necessary, because I use transit for serialisation, take care of timestamps with clj-time/cljs-time and use component

jaen10:11:22

So again, if something's unclear - shoot

jaen10:11:02

@trancehime: actually re-frame doesn't assume datascript IIRC, it uses a single atom. But for something as simple as chat you could probably do without it.

trancehime10:11:20

@jaen: yeah, the examples just use a single atom but basically its explanations hinge on utilizing something like datascript or basically data which could be populated on client-side such as a single app-state ratom. But it just gave me some confusion as at the time I was reading it I had no idea how to process making AJAX calls and then rendering them in the render function. Now I know how to do it though haha

jaen10:11:09

I guess this might be confusing at first.

jaen10:11:04

When I first learned of re-frame instead of using it I actually re-implemented it by going through the readme and source and this let me understand how it works. But that's certainly the long way round.

trancehime10:11:36

If time was something I had, I would have taken time to study the intricacies behind it. Sadly I do not

tragiclifestories10:11:07

I thought of it mainly because it seems like a websocket would be a good candidate for treating as a stream in the FRP kind of way

jaen10:11:24

Yeah, hence the second sentence, I've noticed you're tight on schedule.

trancehime10:11:43

I'm actually behind on schedule because of problems that occurred in my past work that I had to fix urgently

trancehime10:11:43

So, as I understand it, basically when async is started, I don't have to care about how many potential channels or pages I'm going to be having, right?

jaen10:11:55

Ok, basically what I do is sente has this taoensso.sente/start-chsk-router! function which takes two arguments - the receive channel you get out of taoensso.sente/make-channel-socket! and a function that will be called for your message.

jaen10:11:02

They are in the async file for you to read, but basically what they do is they match on the sente message, :chsk/recv is a message that's received from the other side (so from client on server, from server on client)

jaen10:11:47

And I have a multimethod that dispatches on the event, events are 2-tuples [:event-name payload] and I just act accordingly

jaen10:11:53

In this table here you have described what the messages look like - https://github.com/ptaoussanis/sente#now-what

jaen10:11:05

I now see my code is slightly confused as to how it dispatches on event type, you should be able to dispatch just on id in ev-msg (those sente short names are somewhat confusign).

jaen10:11:10

And in the multimethod for event

jaen10:11:14

I do whatever logic I need

jaen10:11:47

If I get :chat/new-message I add the message to atom on the client side, I send it to other connected clients on server side. If I get :chat/new-channel I add new channel, and so on.

trancehime10:11:13

omg. So actually, through using ch-recv and chsk-send! I am basically just manipulating the data structures and then sending it (optionally broadcast it if I need to) to other connected clients.

jaen10:11:50

You send with chsk-send! make-channel-socket! returns

jaen11:11:20

And you don't need to use ch-recv directly, start-chsk-router! sets the event loop up for you.

jaen11:11:25

But yes, that's fairly manual

trancehime11:11:35

Gonna think about this, I have to go home, but I will be back

jaen11:11:08

Sure, if anything's unclear there - feel free to ask. It will also help me, since I want to present to people that cannot into Clojure at all at some point, so any remarks on what's confusing will be helpful.

trancehime11:11:22

i noticed you used component but does it matter much if I don't use it?

trancehime11:11:18

also i will try and see how does start-chsk-router work

jaen11:11:37

No, you don't have to

trancehime11:11:54

Figured, just wanted to be sure

jaen11:11:15

In fact, if you're pressed for time it's probably better you don't, it slows you down somehow for benefits you won't get in a small, throwaway app.

jaen11:11:29

Oh, one thing that's important with sente

jaen11:11:31

(-> bidi-handler
    ring-keyword-params/wrap-keyword-params
    ring-params/wrap-params)

jaen11:11:45

Don't forget about those two middlewares around your ring handler

jaen11:11:00

Otherwise sente won't work and you'll be scratching your head as to why for a good while.

trancehime11:11:09

I already wrap those middleware

trancehime11:11:16

So it's fine

jaen11:11:26

Then good; it's needed for the default implementation of user-id-fn (you don't have to provide one, like I did)

jaen11:11:15

I left it there because I cannibalised it from another project where the user-id depended on authentication, you have to provide user-id on your own in such cases

jaen11:11:37

If your app doesn't need auth (you for example identify by usernames only) then no need to care about that.

trancehime11:11:41

incidentally i have used friend for auth using a custom workflow, yet i dont want to open a connection until after they authenticate

trancehime11:11:29

thats been making my head spin a little

jaen11:11:40

Hah, friend.

jaen11:11:47

I don't pretend to understand it at all.

jaen11:11:59

I've use buddy instead, it's considerably simpler and more easily understandable.

jaen11:11:46

Kind like the difference between devise and sorcery in Ruby.

trancehime11:11:22

ANyway, is it posible for me to control when does the ws connection get opened?

trancehime11:11:37

most examples i saw start async immediately

trancehime11:11:56

I saw a blog entry of someone wrapping the sente routes behind friend/authenticated but that seeemed really weird

jaen11:11:11

Sure, it depends entirely on you when you call make-channel-socket!

jaen11:11:27

In the project I've cannibalised that presentation code from

jaen11:11:44

I have a one step of indirection more

jaen11:11:22

I have a core.async channel that I can queue messages to send on and I connect when I want to.

jaen11:11:16

And when I connect I just run a go-loop that takes the messages from the channel and sends them, when connection breaks/disconnects, I stop the go-loop.

jaen11:11:40

But most of the time connection ASAP is what you do; you don't have to though, entirely up to you.

jaen11:11:50

As for wrapping sente routes behinf friend/authenticated

jaen11:11:04

That needs a bit explanation on how sente works, but just a bit

jaen11:11:14

It doesn't connect with ws immediately

jaen11:11:22

it first connect with AJAX to handshake

jaen11:11:50

And then if client supports it, it switches over to websocket, otherwise simulates it by (I think) long polling

jaen11:11:03

user-id-fn for example gets run on the AJAX handshake request

jaen11:11:13

So wrapping with friend/authenticated makes sense

jaen11:11:27

It puts the authenticated user data into the request map

jaen11:11:35

Which you can then access in user-id-fn

jaen11:11:46

To use a user id that's unique to this user

jaen11:11:55

(probably his DB record id)

trancehime11:11:47

now it makes sense

jaen11:11:49

I've did it a bit differently, but I removed it from the presentation since it complicates things a little

jaen11:11:05

Because I use JWT for authentication instead of cookies

jaen11:11:59

I just decided I'll wrap all my messages to look like so {:payload actual-message :something-else i-need} and set user id that way

jaen11:11:58

When user authenticates I return him the id he should now have, he disconnects and reconnects with it

jaen11:11:11

This way I can avoid using cookies/session sente requires by default.

jaen11:11:22

But if you already use them then no need to jump the hoops

jaen11:11:15

But such wrapping is nifty if you for example generate uuid for each message and can attach metadata to which message it was a reply (if you need so).

jaen11:11:45

Hopefully you can get friend to cooperate easily, otherwise switching to buddy might be easier.

trancehime11:11:19

my auth is working fine wihout ws at the moment

jaen11:11:32

So it should hopefully just work if you wrap sente routes (not sure if both or only the handshake one) and base user id on things friend assoc'd into the request map.

trancehime12:11:26

Yeah I was just using the default for friend

trancehime12:11:27

omg, that debug message. {:top "kek"}

mike13:11:17

is there a page which actually links to the app written in clojurescript?

mike13:11:45

tenzing does not create a project.clj file?

martinklepsch14:11:47

@mike: tenzing uses boot. boot does not use project.clj

mike14:11:40

@martinklepsch: does cursive understand boot? I know it works with project.clj.

mike14:11:40

@martinklepsch: do I have to add the code to my ~/profile.boot (is this where the file is supposed to be?), and then regenerate the boot project all over again?

martinklepsch14:11:02

you can also add it to your local build.boot file but since you might have multple projects/other people not using cursive you most likely want to put it into profile.boot

mike14:11:48

sure, but after adding it to profile.boot, do I have to regenerate the boot project?

martinklepsch14:11:53

@mike: after you’ve added it you just need to run boot lein-generate once and then after you add additional dependencies

martinklepsch14:11:21

@mike: the lein-generate task derives a project.clj from your build.boot so Cursive can parse that.

mike14:11:56

cool. do I have to keep running boot lein-generate in the future to keep the two projects in sync?

martinklepsch14:11:25

yes, when you add dependencies you’ll need to re-run it

eggsyntax14:11:46

I'm working on creating a cljs-compatible js lib on cljsjs, and a clojars lib of my wrapper for that js lib (more details yesterday on this channel, 11:40am-1:30pm). Of those here who are familiar with either or both parts of that process, is there someone willing to be pestered with a bunch of noob questions about it?

eggsyntax14:11:32

Cool, thanks @martinklepsch simple_smile. I'll hit you up in PM.

martinklepsch14:11:42

There’s #C0E66E1H7 as well

eggsyntax14:11:58

Oooh, I didn't see that. I'll use that as well.

mike15:11:54

I do not find (.getElementById js/document "container") intuitive, why not (js/document :getElementById "container")?

cjmurphy16:11:03

After the ( there must be a 'verb'.

cjmurphy16:11:26

The most common type of verb is a function.

cjmurphy16:11:52

The dot denotes calling a method.

mfikes16:11:04

@mike Consider (macroexpand '(.getElementById js/document "container”)) which yields (. js/document getElementById "container”)

mike16:11:14

how about (js/document/getElementById ...)?

thheller16:11:18

(js/document.getElementById "container")?

thheller16:11:54

although the "root" must be a global object, doesn't work with locals

mike16:11:21

wait, (js/document.getElementById "container") works?

mike16:11:35

why does everyone use the other approach?

thheller16:11:13

it doesn't work in all cases like I said

mike16:11:38

sorry, missed that line.

thheller16:11:40

. or .. are the safe choices

cjmurphy16:11:06

What does .. mean?

mike16:11:28

these are weird stuff for people, like me, coming from js land.

mike16:11:53

what is .?

mike16:11:12

is .getElementById a function?

thheller16:11:31

. is a macro

mike16:11:32

I see, what mfikes wrote now makes sense.

thheller16:11:51

somewhat similar to ->

thheller16:11:03

only assumes property access

cjmurphy16:11:09

And the macro is a 'method' macro that grabs the method from the object that comes next. Is that the way it works?

thheller16:11:02

(.getElementById js/document ..) is short for "get property getElementById of js/document and call it with ..."

mike16:11:22

is . specific to clojurescript?

mike16:11:06

is there a property concept in clojure?

thheller16:11:41

pretty much the same applies for CLJS

mike16:11:06

so, is . in clojurescript for javacript interop?

mike16:11:28

can clojurescript also interop with java?

thheller16:11:58

clojure does that 😉

mike16:11:12

so anything that compiles to javascript must be written in pure clojure code?

mfikes16:11:14

@mike: The one odd exception is perhaps in Nashorn simple_smile

thheller16:11:08

well you can use any javascript, wherever that came from

thheller16:11:30

the cljs compiler only compiles cljs

mike16:11:53

I mean, can I import any clojure library into clojurescript code and have that library compiled to javascript?

thheller16:11:12

well maybe if it is .cljc code

thheller16:11:40

but generally no

mike16:11:09

is clojurescript a strict subset of clojure?

mike16:11:10

if so, what is the main difference between the two?

thheller16:11:34

main difference is pretty simple

thheller16:11:37

cljs targets js

thheller16:11:41

clj target the jvm

thheller16:11:55

with all the platform limitations that come from that

mfikes16:11:16

ClojureScript separates compile time from runtime a bit more than Clojure.

mike16:11:03

given that figwheel already autoloads new changes, is there a point of evaluating code in repl, as it happens in clojure?

mike16:11:34

I'm trying to understand why one would want to connect to nrepl and evaluate clojurescript code.

mfikes16:11:59

Hah… Bruce fundamentally challenged the idea of REPL with Figwheel, IMHO. simple_smile

thheller16:11:37

nah a REPL is still useful

thheller16:11:50

why reload an entire file to eval one form

mike16:11:05

I can see some use cases, but figwheel removes a lot of them.

mike16:11:00

well, it all gets reloaded when the file is changed anyway ¯\(ツ)

chris16:11:53

I think devcards was an even bigger innovation than just figwheel, personally

chris16:11:07

(in terms of getting rid of the repl in the equation)

mike16:11:36

I just created a new project using https://github.com/martinklepsch/tenzing , it requires boot-reload.

mike16:11:08

does boot-reload use figwheel, or devcards, or none?

chris16:11:32

it’s own thing, I would think. figwheel uses lein

jaen16:11:03

Yeah, it does ~the same figwheel does, but is different codebase.

mike16:11:23

so where does devcards fit in here?

jaen16:11:36

I think there are some thing that could be improved if they re-used figwheel code but don't really know what they are, since I didn't encounter any.

mike16:11:36

do I not need devcards when using boot?

jaen16:11:47

This is really orthogonal

chris16:11:21

devcards isn’t really the same thing, it works with figwheel but doesn’t duplicate its functionality

jaen16:11:07

Yeah, figwheel is used only for convenience with devcards, so you can get your devcards reloaded on the fly; I imagine you can use devcards with boot as well, I just didn't have an occasion to try yet

mike16:11:07

oh, so it doesn't work with boot-reload?

martinklepsch16:11:34

people are using devcards + boot

jaen16:11:38

I didn't say it doesn't, it's just I didn't see an example. And it looks like there is one, thanks.

martinklepsch16:11:43

there are some other examples as well

mike16:11:02

thank you.

mike17:11:57

is reagent a wrapper for a specific version of react, or can it be used with any react version? (sorry for x-post, #C0620C0C8 is mostly 💤 )

jaen17:11:06

As long as it's < 0.14

mike17:11:09

that old?

mike17:11:12

@jaen 0.14 has been out for a fairly long time, does reagent normally lag behind this much?

jaen17:11:44

I don't think anything in Clojurescript world uses 0.14 (but may be wrong)

jaen17:11:05

7th of October is not that long of a time IMO

mike17:11:06

why is that?

jaen17:11:23

And IIRC this release changes how React works somewhat, doesn't it?

jaen17:11:37

But for exact reasons you would probably have to ask library maintainers

mike17:11:42

I know 0.14 has breaking changes.

jaen17:11:00

Yeah, so possibly that

mike17:11:48

but it does not necessarily mean that when reagent is upgraded to 0.14, codes using reagent will need breaking changes.

mike17:11:20

I assume reaegnt tries to abstract it.

mike17:11:44

but I might be wrong.

jaen17:11:51

Also when you're not using React directly I imagine changes to it are not as important as when you're writing React directly.

jaen17:11:02

Like I said you'd have to ask reagent's maintainers, I can only speculate.

mike17:11:01

is (.-body js/document) excatly the same as (aget js/document "body")?

jaen17:11:45

aget is supposedly for arrays only.

shaunlebron17:11:17

@mike document.body vs document["body"]

thheller17:11:20

(. js/document -body)

thheller17:11:20

but no aget is for arrays

mike17:11:42

so, if I want to protect variable renaming from closure compiler advanced optimizer, I can use aget?

mike17:11:10

not cool?

thheller17:11:15

well yes, but use goog.object.get instead

thheller17:11:34

(js/goog.object.get obj "stuff")

thheller17:11:11

aget works though, just not recommended

mccraigmccraig17:11:10

@mike: reagent started upgrade to 0.14 on 8 october ! https://github.com/reagent-project/reagent/commits/master?page=2 i guess the changes are somewhat more than trivial

mccraigmccraig17:11:59

and there will be some breaking changes, though i don't think these will break any of my code https://github.com/reagent-project/reagent/commit/348ac4aaf86dd120d0aa254dc06c5efa5991ce22

dreic19:11:57

ubuntu users here? How do I get started? Java problem pops up first. Which version do I take?

dreic19:11:20

probably off topic 😄

nbdam20:11:02

Does anybody know how to extend Closure library classes with cljs? I am trying to use closure rich text editor and need to write a custom plugin. It would be nice to do it in cljs...

nbdam20:11:20

The code I would like to do should do something like this:

goog.editor.plugins.BasicTextFormatter = function() {
  goog.editor.Plugin.call(this);
};
goog.inherits(goog.editor.plugins.BasicTextFormatter, goog.editor.Plugin);


/** @override */
goog.editor.plugins.BasicTextFormatter.prototype.getTrogClassId = function() {
  return 'BTF';
};

juhoteperi20:11:53

@dreic: openjdk-8-jdk should be available in Ubuntu 15.10 and to install Oracle JDK 1.8 on older versions you can use this PPA: https://launchpad.net/~webupd8team/+archive/ubuntu/java

dreic20:11:28

@juhoteperi: so openjdk is fine, too?

dreic20:11:14

ok, prefer that.

dreic20:11:27

Despite the 99.99% I did find a typo in the quick start guide.

dreic20:11:37

there are at least two '.' instead of ':' right before code sections simple_smile

nbdam20:11:00

thanks @juhoteperi this looks like it will simple_smile

clojuregeek21:11:39

if some has a few minutes, i need some help getting data out of my channel ... in the cljs repl

simple-dash.core=> (def a (get-data))
#'simple-dash.core/a
simple-dash.core=> a
#object[cljs.core.async.impl.channels.ManyToManyChannel]

clojuregeek21:11:26

I tried (go (println (<! a)) which doesn't seem to work

val_waeselynck21:11:59

@clojuregeek: if you have used enable-console-print! it's normal you don't see it in the repl I think

val_waeselynck21:11:05

if you really want to interact directly with the future value in the REPL, I think your best shot is putting it in an atom.

clojuregeek21:11:44

yeah i don't see anything in the browser... ok i'll try putting in an atom

jaen21:11:04

(go (.log js/console (<! a)))

jaen21:11:13

Should print you in the browser console

clojuregeek22:11:53

hmm ... maybe the channel is returning null Uncaught Error: No protocol method ReadPort.take! defined for type undefined:

jaen22:11:02

I don't think channels can return nils, unless they are closed that is

val_waeselynck22:11:26

most likely a is undefined