XSF Discussion - 2018-02-19


  1. jonasw

    anyone here at whom I can bounce an idea I had for ecaps2?

  2. jonasw

    (otherwise I’ll take that to the list, but from experience, I won’t get a lot of feedback there :/)

  3. Zash

    How much context is needed?

  4. jonasw

    if you know how caps (XEP-0115) works, it’s probably fine

  5. Zash

    How much coffee is needed? :)

  6. jonasw

    uh, maybe a bit, but I’m not sure. I don’t drink coffee :-)

  7. Zash

    Shoot. What's the worst that can happen? :)

  8. jonasw

    ühah

  9. jonasw

    hah

  10. jonasw

    so I was wondering what if we don’t have clients inject the caps into the presence, but instead use a nonza/stream-level element to let the server know about the caps.

  11. jonasw

    the server would then re-send presence and take care of injecting caps updates in presences.

  12. jonasw

    receiving entities would see the caps in presence as usual.

  13. jonasw

    this saves the client from re-sending (non-directed) presence when the caps change (server would re-broadcast)

  14. jonasw

    I literally just had the idea. I’m not 100% sure how the interaction with stream management would be.

  15. jonasw

    (but probably it would be "re-send your caps to the server after resumption, unless you’re 100% sure your previous caps update came through")

  16. jonasw

    the rationale why this might be nicer for the client is that presence is already a rather complex beast, in the context of MUC, in the context of vcard avatars and possibly other things (if we want to integrate chat states into that for example)

  17. Zash

    You could transmit your entire disco#info blob, then the server could do the caps/ecaps/magic for you

  18. jonasw

    very interesting point

  19. jonasw

    and do all other sorts of interesting things with it even

  20. jonasw

    (e.g. what people proposed with publishing a subset/superset of all client features in a PEP node)

  21. Zash

    Would probably tie in nicely with some future client registration

  22. jonasw

    client registration?

  23. jonasw

    like, device keys?

  24. Zash

    The server having some idea of which clients you have.

  25. jonasw

    yes

  26. Zash

    Sounded like people wanted something in that direction.

  27. Zash

    jonasw: I think we should be careful with just throwing non-stanzas at everything

  28. jonasw

    an IQ would work just as well here

  29. jonasw

    (I actually put some thought into nonza vs. message for server-originated pushes and there nonza was fine and semantically made more sense, so I just transferred that to client-originated pushes too; I might be wrong here)

  30. jonasw

    (I’m not sold on using nonzas)

  31. Zash

    Caps are a property of what, exactly?

  32. jonasw

    the client.

  33. jonasw

    (or server respectively)

  34. jonasw

    (entity.)

  35. Zash

    Not the stream itself.

  36. jonasw

    yeah

  37. jonasw

    probably makes sense to put them as IQs or something

  38. Zash

    I was thinking basically just disco#info in an iq-set would be nice and simple

  39. jonasw

    yeah

  40. jonasw

    so clients wouldn’t have to calculate *their own* hashes anymore, but they might still want to calculate other peoples hashes and keep a cache.

  41. jonasw

    for directed presence, sending an "empty" directed presence would make the server inject caps as needed. is that a privacy issue?

  42. jonasw

    probably not, because who knows your resource can disco#info you anyways.

  43. Zash

    yup

  44. jonasw

    cool

  45. jonasw

    I hear a namespace bump rolling along.

  46. jonasw

    or maybe not.

  47. jonasw

    gotta think about that

  48. Zash

    New namespace, disco#push or something?

  49. jonasw

    nah, I need to think whether caps2 itself needs a bump for this. But it might actually not.

  50. Zash

    Does ecaps2 replace disco?

  51. jonasw

    no

  52. jonasw

    not entirely I think

  53. Zash

    caps is a separate thing right

  54. jonasw

    it might save you a lot of disco#info-ing, but you still need to support xep-0030

  55. jonasw

    and then I’ll need to make an implementation in prosody to show that it works :D

  56. Zash

    PoC all the things!

  57. jonasw

    maybe I’ll sink my afternoon in that.

  58. Ge0rG

    jonasw: awesome idea, I'm all for making the client dumber again

  59. Ge0rG

    jonasw: beware directed MUC presences though, they are broken already.

  60. jonasw

    Ge0rG, what’dya mean?

  61. jonasw

    server wouldn’t resend directed automatically, client needs to do that (server just injects caps hashes)

  62. Ge0rG

    jonasw: I _think_ I sent that to standards recently, but can't find. When the MUC changes your nickname, your server will later send your "directed" unavailable presence to the old nickname.

  63. jonasw

    yeah, heard about that

  64. Ge0rG

    jonasw: shouldn't the server resend all directed presences on a caps change?

  65. Zash

    Yeah, the MUC changing your nickname causes all sorts of headaches

  66. jonasw

    Ge0rG, I looked at how {xep 0398} does it, and it doesn’t resend directed either

  67. Bunneh

    Ge0rG: User Avatar to vCard-Based Avatars Conversion (Standards Track, Experimental, 2018-01-25) See: https://xmpp.org/extensions/xep-0398.html

  68. Ge0rG

    jonasw: maybe it's just an oversight by the XEP authors?

  69. Ge0rG

    it would make sense to resend.

  70. jonasw

    maybe; we should ask daniel about this

  71. jonasw

    maybe; we should ask daniel about this ^

  72. Zash

    jonasw: Nothing says you can't have the server query disco#info like normal and then generate caps and ecaps2 for it.

  73. Zash

    For legacy clients etc

  74. jonasw

    Zash, true; I’m not sure why you’re mentioning that though.

  75. Zash

    Thinking out loud

  76. jonasw

    (and it would require polling)

  77. jonasw

    ok

  78. Ge0rG

    it would add some nastyness into the protocol flow

  79. Zash

    Prosody already does it, but discards the response, save for the PEP +notify items

  80. Ge0rG

    1. client sends online presence 2. server delays outbound presence, asks client for disco#info instead 3. the client sends directed presences all around 4. eventually, the client responds to disco#info 5. the server can now inject and forward

  81. Ge0rG

    is +notify part of disco#info?

  82. Zash

    Ge0rG: Yes

  83. Ge0rG

    Zash: which question was that a response to?

  84. jonasw

    I wonder if we should be stripping +notify from things sent to peers while we’re at it.

  85. Zash

    Ge0rG: +notify goes in disco#info

  86. jonasw

    but probably not.

  87. Zash

    Can we forklift PEP into being account based that way?

  88. Zash

    As in, subs are between accounts, not between remote account and specific resources

  89. Ge0rG

    wasn't there a discussion of making PEP account-based just some days ago, on this MUC?

  90. jonasw

    I must’ve missed it

  91. jonasw

    Zash, it could be a good first step with the superset thing

  92. jonasw

    would probably require an update to {xep 0163}

  93. Bunneh

    jonasw: Personal Eventing Protocol (Standards Track, Draft, 2010-07-12) See: https://xmpp.org/extensions/xep-0163.html

  94. Ge0rG

    Zash: what's up with Bunneh? I'm missing it sorely.

  95. Zash

    Bunneh: ping

  96. Bunneh

    Zash: pong

  97. Zash

    Bunneh: version Ge0rG

  98. Bunneh

    Zash: Ge0rG is running yaxim version 0.9.2-95-gcab21a3 on Android

  99. Ge0rG

    That's a lie.

  100. jonasw

    Ge0rG, your statement is confusing to me: https://sotecware.net/images/dont-puush-me/v7RTW5gsnGjnTE5G6QahCIPsruzqV3-1IRISifpDBRI.png

  101. Zash

    Ge0rG: Stanza reply id duplication causing you problems?

  102. Ge0rG

    Zash: it won't join my MUC.

  103. Ge0rG

    jonasw: why are you quoting by image? :P

  104. jonasw

    Ge0rG, that is a very good question I can’t really answer

  105. jonasw

    I guess that’s what happens when you have a scrot-scp-xclip pipeline bound to something which is close to a hotkey

  106. Ge0rG

    I don't even want to know what "scrot" is the abbreviation for.

  107. jonasw

    Ge0rG, it’s not an abbreviation, it’s the name of a tool.

  108. jonasw

    I find it confusing, too.

  109. Ge0rG

    that's what she said?

  110. jonasw

    cf. http://manpages.ubuntu.com/manpages/precise/man1/scrot.1.html

  111. jonasw

    argh

  112. jonasw

    I’ll just head out now :P

  113. Zash

    Ge0rG: I'm going to guess that it thinks that it is joined. Or doesn't support mediated invites. Or both.

  114. jonasw

    see you later

  115. Ge0rG

    Zash: can't you kick its lazy bottocks?

  116. Zash

    I can update its server

  117. Ge0rG

    If that will make it rejoin my MUC?

  118. Zash

    Setting up prosody-trunk (1nightly844-1~trusty) ... prosody stop/waiting prosody start/running, process 1714

  119. Ge0rG

    When doing disco#info on my own server, how am I supposed to differentiate a MUC service from an IRC transport?

  120. Zash

    Are you supposed to at all?

  121. Ge0rG

    I'm sure it won't end up well if I try to create a private MUC on biboumi.

  122. Zash

    Uh, fun

  123. Ge0rG

    Wasn't there a disco#info item telling a client that it may create new MUCs on that service?

  124. Zash

    I'm not aware of such a feature

  125. Zash

    Not that many features depend on who asks

  126. Zash

    Or?

  127. Ge0rG

    ...that it is possible to create new MUCs on this service.

  128. Ge0rG

    XMPP is full of fail.

  129. Zash

    You could look for the feature "http://jabber.org/protocol/muc#unique"

  130. Zash

    It's pretty useless tho

  131. Zash

    It would imply that it's possible to create randomly named MUCs... for someone... maybe

  132. Ge0rG

    Zash: that's not part of 45?

  133. Zash

    -xep 307

  134. Bunneh

    Zash: Unique Room Names for Multi-User Chat (Standards Track, Deferred, 2011-11-10) See: https://xmpp.org/extensions/xep-0307.html

  135. Zash

    It was broken out IIRC

  136. Zash

    The Prosody implementation just returns an UUIDv4

  137. Ge0rG

    Ah, it's type=irc as opposed to type=text. Yay.

  138. Zash

    How is irc not text?

  139. Zash

    And how do you know that room creation is not restricted to admins?

  140. Ge0rG

    I can't.

  141. Ge0rG

    I can't fix all problems of XMPP. Not today.

  142. Maranda

    It's all an iconian plot I tell you. 🙄🖖

  143. mathieui

    Ge0rG, but you have to

  144. Ge0rG

    mathieui: maybe if somebody will pay me.

  145. Guus

    Ge0rG: do you accepty payment in the form of stickers?

  146. Ge0rG

    Guus: I'll ask my landlord.

  147. Ge0rG

    TBH I never considered putting stickers onto my Laptop, my car or any other item. Not sure why.

  148. Guus

    Ge0rG: Cut out the middle man! Stickers make for nice decoration for inside a cartboard box under a bridge!

  149. Guus

    Ge0rG: same here.

  150. Ge0rG

    Guus: great idea! But living under the bridge isn't free either.

  151. Zash

    Extract tolls from passing goats?

  152. Ge0rG

    I could probably obtain sufficient amounts of food by dumpster diving. But how should I handle the -5°C temperatures

  153. jonasw

    Ge0rG, mine bitcoin on your laptop

  154. jonasw

    oh wait.

  155. Guus

    I like how we as a community are coming together to tackle both Ge0rG's residential issues as well as all of XMPPs problems.

  156. Ge0rG

    Guus: I'm very grateful for that effort.

  157. Ge0rG

    ,oO( does "being grateful" actually mean "being full of grates"? )

  158. Kev

    Full of gratitude, I think, but your understanding could be good too.

  159. Ge0rG

    In that case I prefer to be gratitudeful, thanks.

  160. Zash

    Hmm, gratäng?

  161. flow

    jonasw, I'm not sure if client implementations would become easier. As far as I remember, implementing caps in Smack was not really challenging.

  162. flow

    besides the i;octet collation, which is possilby underspecified in xep115 (but thankefully not in xep390)

  163. Zash

    I would be happy if, when I use `clix raw` and send presence, it doesn't instantly drown in so many disco#info queries and other stuff that the terminal crashes.

  164. Zash

    (rlwrap doesn't always handle syntax highlighting all that well)

  165. flow

    Are there so many implementations that fetch disco#info unconditionally after a caps update? Are impls supposed to do that?

  166. flow

    Zash, what's clix?

  167. jonasw

    Zash: thats separate though, we can have query interception as-is

  168. Kev

    Command-line XMPP.

  169. Kev

    But yes, I'd expect clients to disco when they see a new caps.

  170. flow

    Why?

  171. Zash

    flow: http://code.matthewwild.co.uk/clix/

  172. Kev

    To know what features are supported by contacts.

  173. jonasw

    flow: decoupling caps from presence has the advantage of being able to use caps without presence

  174. flow

    jonasw, is it really caps that you decouple, not disco#info?

  175. Link Mauve

    “15:54:05 flow> jonasw, what do you think about the xep390 optimization to move the disco#info result from the client to the server?”, I have an experimental module doing that for 0115, caching the disco#info and the 0115 node in the session table, and answering iqs requesting it automatically.

  176. jonasw

    and if we push disco#info and let the server deal with it, thats nice I think

  177. Link Mauve

    A few things to fix and it should end up in prosody-modules.

  178. jonasw

    also I'm on mobile

  179. jonasw

    gotta go

  180. flow

    Kev, but why do you need to know the features right after the caps update? And not, let's say, when you show the contact list in the GUI?

  181. flow

    Link Mauve, so xep115 § 8.4?

  182. Link Mauve

    flow, hmm, no, I don’t change anything about what the client advertise, I just request the disco#info when its <c/> changes and answer iqs from external entities instead of routing them to the user.

  183. Link Mauve

    I’m not sure what stripping it would achieve.

  184. Link Mauve

    Other than increase the amount of requests from other entities.

  185. Link Mauve

    And prevent them from using their normal cache mechanism.

  186. flow

    Link Mauve, sorry, I thought that was the xep115 counterpart of xep390 § 6.4 without closing reading it

  187. flow

    So you do xep390 § 6.4 for xep115?

  188. Link Mauve

    flow, yes, except I forgot the third point, will fix.

  189. Link Mauve

    I’ll add a mention of that.

  190. Link Mauve

    And soon will add support for 0390 too.

  191. jonasw

    Link Mauve: sweet! what do you think of the proposed model of pushing disco#info from clients?

  192. jonasw

    so that the server handles hash calculation and presence broadcast?

  193. Link Mauve

    jonasw, would avoid one roundtrip, but it would also require every client to change, so I’m not sure it’s really useful.

  194. Link Mauve

    Well, both clients and servers.

  195. jonasw

    Link Mauve: we need to change clients for 390 anyways 😺

  196. jonasw

    (and servers)

  197. Link Mauve

    Uh, why?

  198. Link Mauve

    I just had the idea to let the server compute 0390 and insert it in the presence if the client only had 0115.

  199. jonasw

    Link Mauve: because they need to emit/process 390 hashes instead of / in addition to 115 hashes.

  200. Link Mauve

    That would immediately increase adoption and usefulness.

  201. jonasw

    yeah

  202. jonasw

    indeed

  203. jonasw

    I'm working on an update to 390 btw. I'll add that.

  204. Link Mauve

    So I’ll continue this Prosody module in that direction, and you fix all of the clients in the meantime. :)

  205. jonasw

    I won't fix pidgin 😼

  206. Ge0rG

    jonasw: but you could burn it with fire.

  207. jonasw

    Ge0rG: having the server re-send directed presence to MUCs also has interesting isszes with the proposed no-join (since errors need to be handled) and possibly passwords etc.

  208. jonasw

    I think thats a can of worms I don't want to open.

  209. jonasw

    gotta go agaib

  210. jonasw

    *again

  211. jonasw

    re

  212. jonasw

    Link Mauve, so, others (I think the MIX folks) have already indicated interest in pre-presence disco#info from the client. XEP-0390 actually already specifies that with an IQ (even though that IQ only carries caps instead of disco#info). the change would be to make clients always use the IQ instead of presence to send caps to their server (and the server takes care of injecting caps in presence and re-broadcasting non-directed presence when caps change)

  213. jonasw

    Zash proposed to change the IQ to actually contain the whole disco#info data instead of only the caps, which I think is neat. It allows the server to do all kinds of interesting things, like do the 115+390 optimization without having to ask the client for disco#info if it doesn’t have the hashes in the cache.

  214. Zash

    Wasn't there a proposal for rolling auth, resource binding and some session initialization into one transaction? Maybe something Kev or Dave talked about

  215. mathieui

    https://opkode.com/blog/xmpp-chat-badge/ this is neat (from jcbrand)

  216. Zash

    Now taking bets on how long it would take to make that as a prosody module

  217. Maranda math.random(100)

  218. Maranda

    Bunneh¡! 🤣

  219. Guus

    ah, we have that for user presence, but not mucs. That's a nice idea

  220. Guus

    I shall shamelessly copy that.

  221. Kev

    References to pubsub items. Thoughts?

  222. Kev

    We're about to allow references to FDP forms in Swift, so we want a reference to a pubub item.

  223. goffi

    Kev: I would like to reference pubsub items for mentions in blog post too

  224. goffi

    Kev: I though a super simplified xpath compatible syntax would be useful

  225. goffi

    +t

  226. Kev

    We could just do this as any other URI reference, pointing at the pubsub item, but if we did a specialist 'pubsub' reference we could also include the namespace.

  227. goffi

    Kev: URI is not enough, we need to know if we reference text or XHTML body

  228. Kev

    I don't follow.

  229. intosi

    goffi: for pubsub?

  230. goffi

    intosi: for microblog items

  231. intosi

    But that's pointing to stuffs inside a pubsub item payload, which is probably beyond what Kev;s intending here.

  232. Kev

    I'm talking about just pointing to a pubsub item.

  233. goffi

    intosi: yes it's pointing inside payload, that's why I'm mentioning simplified xpath

  234. goffi

    OK

  235. goffi

    so that's an other issue I'm talking about then.

  236. Kev

    I think so, yes.

  237. SamWhited

    Speaking of xpath, does anyone do some form of stanza matching that doesn't involve xpath? If so, what do you do? I've been struggling for ages to come up with a way to match handlers in an XMPP library that I don't end up despising and throwing out.

  238. waqas

    SamWhited: Seen Prosody's approach?

  239. SamWhited

    waqas: I must have used it when writing plugins, but I can't for the life of me think what it is?

  240. waqas

    For each stanza, we fire some events on our event bus. Event names like "iq", "iq/{xmlns:tagname}", etc.

  241. waqas

    Because Prosody is a server, we actually do "iq/{bare|full|self|host}/…", etc, since the target JID's nature actually matters for server routing.

  242. SamWhited

    ah yes, I remember. What if, for example, multiple things listen for an IQ and both try to reply to it?

  243. Zash

    iq/{host,bare,full}, iq-{get,set}/{host,bare,full}/xmlns:name

  244. waqas

    Our event bus is a priority queue, and the first handler to indicate it has handled stops the event chain.

  245. SamWhited

    *nods* that makes good sense

  246. waqas

    Handlers can be registered with priority, so e.g., a privacy list handler may want to have a higher priority than the actual routing. Default stuff is priority 0.

  247. SamWhited

    I actually had something similar to that a while back (except it was chains of function calls similar to the HTTP middleware pattern, and any of them could short circuit the pattern). I can't remember why I didn't actually end up using it now though…

  248. SamWhited

    If multiple things register with the same priority what ends up happening?

  249. Zash

    Random order basically.

  250. SamWhited

    I think the reason I didn't do something similar is that I needed to match initially on the IQ start element token to route to the IQ handler chain, but then in there I needed to match on the payload, but I didn't have a good way to pass both that token and the stanza start token on.

  251. SamWhited

    But maybe I should give up and just always decode the entire IQ as soon as I receive the start token and pass a representation of the entire thing down through the chain

  252. waqas

    We just have mod_iq hook the top-level IQ event, and it then fires the sub-event :)

  253. jonasw

    FWIW, aioxmpp lets you match IQs requests by payload (only namespace+localname essentially) and get vs. set

  254. Zash

    Prosody would parse the entire stanzas before fireing events for them

  255. jonasw

    that, too

  256. waqas

    Full xpath is overkill for XMPP routing

  257. jonasw

    yes

  258. Zash

    At least in a server

  259. SamWhited

    I suppose I'll have to do that, right now my handlers look something like: HandleXMPP(xmlstream.TokenReadWriter, *xml.StartElement)

  260. waqas

    SamWhited: Are you trying to avoid parsing into a DOM immediately?

  261. jonasw

    for things like pubsub where you’d want to match on deeper things, the pubsub service actually eats all pubsub-related things from the stream and emits its own events

  262. SamWhited

    waqas: yah, it's a tad bit more expensive so I was hoping to do the match and decide if I need to do it or not first, but I'm starting to think there's no good way to do that

  263. edhelas

    https://instantdomainsearch.com/articles/streaming-json-jsons/

  264. waqas

    SamWhited: I'd advise against it. The very minor speedup isn't worth the increased code complexity and mental overhead, except for very selected pieces of software where you must have every fraction of perf.

  265. waqas

    And you are parsing the whole thing anyway, the DOM cost isn't actually much (though non-zero, hence my experiments with in-place alloc-free DOM construction).

  266. SamWhited

    Yah, I say "parsing" but that's not actually the expensive part since I have to do that anyways, it's allocating a place to store some generic representation of it that's expensive.

  267. SamWhited

    I actually don't have a decent way to represent a generic blob of XML either, but that's not the end of the world, I've written one for the (terrible) xml library I'm using, so I could probably copy/paste that until it gets merged upstream.

  268. waqas

    What I mean is that that allocation is a fairly small fraction of the allocation that's happening anyway in your XML parser. Every element name, attribute name, attribute value, etc is causing at least one allocation.

  269. SamWhited

    It's true; I like the idea of being able to swap my inefficient XML library out for something a bit better later though and not have my code be the bottleneck

  270. waqas

    Just give in and refactor later. Bets on it not happening anytime soon? :)

  271. SamWhited

    Yah, that's probably a good idea. Maybe I'll try the middleware-style approach again and then if I can't make that work in a reasonable way fall back to parsing the entire stanza up front.

  272. waqas

    The reason why I haven't focused too much on it is that it simply isn't the bottleneck. In Prosody, I can do 100k stanzas/sec on this old macbook. And profiling does not put memory allocation as being item #1.

  273. Zash

    The string interning Lua does probably helps a fair bit

  274. waqas

    (standard microbenchmark disclaimers apply)

  275. waqas

    Zash: No, those don't save us. While it has a few tricks, expat is doing many allocations.

  276. waqas

    In our case, the networking stack is bottleneck #1 (including the kernel, luasocket and net.server), the whole parsing stage (expat + DOM construction) is #2, serialization is #3. All this for a very simple full JID to full JID IQ. Doesn't change much for other stanza types, except stanzas that cause broadcasts and IO are complex.

  277. SamWhited

    Right now for me parsing JIDs is the most expensive part of the stack, but I've gotten that down to be fairly quick (especially if the JIDs mostly end up being ascii)

  278. waqas

    Turn on any IO activity (MAM, logging, etc), and boom, it suddenly overshadows everything else combined

  279. Zash

    Heh, like debug logging

  280. Ge0rG

    Debug logging is a fraction of my I/O, compared to gazillions of chatstates in MAM.

  281. SamWhited

    In a former life though parsing the token stream into some form of usable object was very expensive though, and I'd like to shoot for that sort of scale. I can't do it right now because of the XML library, but it would be nice to be able to do it if I were to swap that out in the future.

  282. Zash

    I'm pretty sure most of my overhead while dev'ing is the drawing of syntax-highlighted stanzas in X

  283. Kev

    Overhead for clients and servers is completely different.

  284. Kev

    The most expensive thing Swift does is rendering a roster.

  285. Kev

    Well, s/rendering/constructing and rendering/

  286. Ge0rG

    If I were start today, I'd go with some dynamic language that has primitives to convert between objects and their stream representation, and ignore performance.

  287. waqas

    Kev: That's very true. And many clients do synchronous UI updates. Gajim and others do very badly when a bunch of stanzas show up..

  288. Ge0rG

    ...and then end up with a situation where remote entities can override my objjects' metadata pointers.

  289. SamWhited

    Indeed; luckily I'm not doing any of that, but I do get frustrated when Gajim completely locks up for a minute or so during the initial presence flood on a big roster

  290. Kev

    Swift does synchronous UI updates, but each one is injected into the UI's event loop individually, so unless the UI framework (Qt) is being daft, you'd need one very heavy stanza to freeze the UI.

  291. SamWhited

    Pushed up my current experiment which didn't end up working out, in case anyone's interested: https://godoc.org/mellium.im/xmpp/mux

  292. SamWhited

    The idea being that you match on the start token and could nest the multiplexers, but in practice you always need the top level stanza's information in whatever handler ends up replying.

  293. moparisthebest

    hmm mux was the name I was rooting for as the mix replacement people actually implement to replace muc with

  294. SamWhited

    oh yah, I would probably be sad if I called this package that and then ended up wanting to implement that later. Maybe "router" would have been a better name for this one. Oh well, it will end up being deleted anyways.