This version (2017/05/27 13:44) is a draft.
Approvals: 0/1

[01:49:35] * ChanServ sets mode: +o purplefox [02:50:07] * ChanServ sets mode: +o purplefox

[09:28:20] * ChanServ sets mode: +o purplefox [09:40:57] <temporalfox> jtruelove hi [09:41:17] <temporalfox> pmlopes hi I have a couple of questions for you [09:41:34] <pmlopes> hi [09:42:45] <temporalfox> in vertx.x web or redis/jdbc do we have use case with List/Set containing null ? [09:43:40] <pmlopes> as argument or as reply? [09:43:54] <temporalfox> both :-) [09:43:54] <pmlopes> or it doesn't matter? [09:44:08] <temporalfox> I'm figuring out the current javascript support for nullable [09:44:38] <temporalfox> and the reality of the current apis [09:44:44] <temporalfox> if we really need/use this feature [09:45:00] <temporalfox> I believe it makes sense for data stuff that can have null return or null insert [09:45:37] <temporalfox> as you worked a bit on database stuff (redis / jdbc) I wnated to check with your the use cases [09:45:40] <pmlopes> i am looking at redis code and a list might contain null values since it is a perfect valid for redis [09:45:53] <temporalfox> if we need it and then we need to properly support it in the codegen TCK [09:45:54] <pmlopes> i even need to encode them in a special way [09:46:13] <temporalfox> ok [09:46:21] <temporalfox> so that would be an argument [09:46:33] <pmlopes> oh and i know that we also need it for the jdbc client [09:46:46] <temporalfox> what type is it ? [09:46:55] <temporalfox> List<String> ? [09:47:21] <pmlopes> oh no, for jdbc it is a json array [09:47:34] <temporalfox> json is different [09:47:43] <pmlopes> when you have query placeholders ? they can be null [09:47:57] <temporalfox> so what do we have for List/Set/Map ? [09:48:43] <pmlopes> humm in that case we could deprecate the redis API and propose a new one using JsonArray [09:49:17] <temporalfox> jdbc seems to use JsonArray [09:49:20] <pmlopes> for a quick find and count it seems that we would need to deprecate 34 method :| [09:49:20] <temporalfox> in SQLConnection [09:49:40] <temporalfox> pmlopes what do you mean ? [09:49:56] <pmlopes> no, sorry in redis, in redis [09:50:40] <pmlopes> in redis there are 34 methods that take List<String> and they can have both null or not null values, however i think we could propose a API update to replace that with JsonArray [09:51:02] <temporalfox> like [09:51:03] <temporalfox> RedisClient evalsha(String sha1, List<String> keys, List<String> values, Handler<AsyncResult<JsonArray» handler); [09:51:10] <pmlopes> yes [09:51:12] <temporalfox> I think it's fine to have nullable [09:51:28] <temporalfox> if it's string I think List<String> is better [09:51:32] <temporalfox> and we should keep it [09:51:44] <temporalfox> my point isthat I'm not sure JavaScripr properly supports null in lists [09:52:01] <pmlopes> ['a', null] is perfectly valid [09:52:27] <temporalfox> ok [09:52:41] <temporalfox> I think we miss at least TCK use cases [09:52:50] <temporalfox> for testing such behavior cross languages [09:53:06] <pmlopes> even more weird stuff like ['a', null, undefined] is allowed ;) don't you love it now :) [09:53:27] <temporalfox> but that would not make sense for vertx [09:53:40] <temporalfox> and that would result in some kind of errors thrown by vertx-lang-js [09:53:45] <temporalfox> wouldn't it , [09:54:40] <pmlopes> it depends if someone is checking for nulls with == then null or undefined are considered null, however if one checks with === then only null is null [09:55:07] <temporalfox> that's why we need a TCK :-) [09:55:08] <pmlopes> the bad side is that if one uses == then 0, '', false are also null :) [09:55:17] <temporalfox> at the moemnt we use typeof on arguments [09:55:29] <temporalfox> and I know that type null is “object” [09:55:32] <temporalfox> in JS [09:55:39] <temporalfox> and the shim is ok with that [09:55:45] <temporalfox> then there is a null check in the conversion [09:55:55] <temporalfox> that means today we don't accept null functions [09:56:10] <temporalfox> for instance vertx.close(null) is acceptable by Vert.x core [09:56:20] <temporalfox> in JS vertx.close(null) throws a TypeError [09:56:21] <pmlopes> where can i add javascript TCK tests? [09:56:33] <temporalfox> that would rather be custom JS cases I think [09:56:36] <temporalfox> as they would contain null [09:56:45] <temporalfox> like you do a Vert.x API in JS [09:56:49] <temporalfox> codegen [09:56:55] <temporalfox> like [09:57:02] <temporalfox> checkList(List<String>) [09:57:06] <temporalfox> and you call it with undfined [09:57:10] <temporalfox> and see what happens :-) [09:57:15] <temporalfox> (tdd style) [09:57:29] <temporalfox> TCK would be more for Nullable collections [09:58:21] <pmlopes> the best way to test for null in js would be (if value === null || value === undefined) [09:58:46] <pmlopes> then we have a behavior like java for instance [10:00:49] <temporalfox> ah you mean that undefined would be considered as null ? [10:01:20] <pmlopes> yes [10:02:03] <pmlopes> and i think that for most use cases in js that is fine specially it what matters to call vert.x code [10:04:49] <temporalfox> yes we should rather be permissive if we pass undefined explictely [10:05:01] <temporalfox> as long as it does not have impacts on overloading :-) [10:07:01] <pmlopes> how do you run the TCK? [10:08:51] * ChanServ sets mode: +o purplefox

[10:09:37] <temporalfox> mvn clean test

[10:09:42] <temporalfox> TCK is ApiTest

[10:09:49] <temporalfox> then you have extra tests around

[10:09:53] <temporalfox> to test special cases in JS

[10:09:58] <temporalfox> and that what you would do

[10:10:13] <temporalfox> but before working on that we should first agree on the global nullable behavior :-)

[10:10:24] <temporalfox> cf my point about nullable function/handler

[10:12:58] <pmlopes> currently in core handlers are not optional, they do not take nulls so we can do the same for JS if handler === null or handler ===undefied then it is a type error i think

[10:14:08] <pmlopes> the undefined is important for cases like: redis.get('key') since i did not pass a second arg js will interpret the second arg as undefined

[10:22:33] <purplefox> pmlopes: temporalfox cescoffier: morning guys

[10:22:42] <temporalfox> hi

[10:22:43] <pmlopes> good morning

[10:22:43] <cescoffier> morning

[10:23:00] <temporalfox> pmlopes null handler has impact on overloading check

[10:23:22] <temporalfox> pmlopes and yes some handlers are optional

[10:23:28] <temporalfox> for instance : vertx.close(null) is valid

[10:23:42] <temporalfox> if you look at Pump implemnetation

[10:23:48] <temporalfox> it calles an handler with null value

[10:27:01] <pmlopes> can you share an example where you're having trouble with js maybe it would be easier for me to fully understand the problem

[10:27:02] <cescoffier> purplefox, pmlopes, temporalfox : if you all agree with the tags proposal, I will update the wiki

[10:27:18] <pmlopes> @cescoffier +1 for the tags

[10:27:26] <temporalfox> pmlopes I sent an example on vertx-dev in reply to myself :-)

[10:27:37] <pmlopes> ok

[11:44:31] <purplefox> temporalfox: hi julien

[11:44:41] <purplefox> temporalfox: quick question on EventBusMetrics:

[11:44:45] <purplefox> void messageSent(String address, boolean publish, boolean local, boolean remote);

[11:45:05] <purplefox> can “local” and “remote” ever be the same?

[11:45:15] <purplefox> if so, why are there two params?

[11:55:07] <temporalfox> purplefox it can be true/true in case of publish that publish both locally and remote on cluster

[11:56:05] <temporalfox> we should update javadoc to be more precise for implementors

[12:01:29] <purplefox> ok, i see thanks

[12:01:57] <cescoffier> pmlopes: did you change the configuration of the vertx-examples build ?

[12:02:24] <pmlopes> i don't think so, why?

[12:02:34] <cescoffier> the build became parameterized

[12:02:40] <cescoffier> by the branch to build

[12:03:12] <cescoffier> well… removing it :-)

[12:03:24] <pmlopes> no i did not do anything on jenkins lately specially about parameterized builds

[12:03:27] <pmlopes> ok

[12:04:26] <cescoffier> the build is failing with “no workspace for vert.x3-examples #640”

[12:10:15] <pmlopes> we also get timeout building web on jenkins it takes more than 30 minutes…

[12:10:18] <cescoffier> ok found the culprit … the github pull request plugin failed

[12:10:27] <cescoffier> 30 minutes !

[12:10:34] <cescoffier> wow, I already increase the timeout

[12:10:40] <cescoffier> 30 min is regally huge

[12:10:47] <pmlopes> yes that is quite stange since it builds in less than 5 on my local machine

[12:10:55] <pmlopes> doing everything including docs

[12:13:13] <pmlopes> there was something wrong with sockjs tests and they blocked for 30 minutes

[12:13:31] <pmlopes> Starting test: SockJSHandlerTest#testNotFound

[12:13:33] <pmlopes> io.vertx.core.VertxException: Connection was closed

[12:13:36] <pmlopes> Thread Thread[vert.x-eventloop-thread-8,5,main] has been blocked for 2990 ms, time limit is 2000

[12:13:38] <pmlopes> Thread Thread[vert.x-eventloop-thread-6,5,main] has been blocked for 2989 ms, time limit is 2000

[12:13:40] <pmlopes> Thread Thread[vert.x-eventloop-thread-8,5,main] has been blocked for 3990 ms, time limit is 2000

[12:13:42] <pmlopes> Thread Thread[vert.x-eventloop-thread-6,5,main] has been blocked for 3990 ms, time limit is 2000

[12:13:44] <pmlopes> Thread Thread[vert.x-eventloop-thread-8,5,main] has been blocked for 4991 ms, time limit is 2000

[12:13:45] <pmlopes> Thread Thread[vert.x-eventloop-thread-6,5,main] has been blocked for 4991 ms, time limit is 2000

[12:13:48] <pmlopes> Thread Thread[vert.x-eventloop-thread-8,5,main] has been blocked for 5990 ms, time limit is 2000

[12:13:50] <pmlopes> io.vertx.core.VertxException: Thread blocked

[12:13:52] <pmlopes> at io.vertx.core.http.impl.ClientConnection.endRequest(ClientConnection.java:339)

[12:13:54] <pmlopes> at io.vertx.core.http.impl.HttpClientRequestImpl.connected(HttpClientRequestImpl.java:552)

[12:13:56] <pmlopes> at io.vertx.core.http.impl.HttpClientRequestImpl.lambda$connect$72(HttpClientRequestImpl.java:515)

[12:13:58] <pmlopes> at io.vertx.core.http.impl.HttpClientRequestImpl$$Lambda$15/1101184763.handle(Unknown Source)

[12:14:00] <pmlopes> at io.vertx.core.http.impl.ConnectionManager$ConnQueue.lambda$getConnection$55(ConnectionManager.java:92)

[12:14:02] <pmlopes> at io.vertx.core.http.impl.ConnectionManager$ConnQueue$$Lambda$128/234250762.handle(Unknown Source)

[12:14:04] <pmlopes> at io.vertx.core.impl.ContextImpl.lambda$wrapTask$3(ContextImpl.java:335)

[12:14:06] <pmlopes> at io.vertx.core.impl.ContextImpl$$Lambda$12/1908698042.run(Unknown Source)

[12:14:08] <pmlopes> at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:358)

[12:14:10] <pmlopes> at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357)

[12:14:12] <pmlopes> at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112)

[12:14:14] <pmlopes> at java.lang.Thread.run(Thread.java:745)

[12:14:18] <pmlopes> Thread Thread[vert.x-eventloop-thread-6,5,main] has been blocked for 5990 ms, time limit is 2000

[12:14:20] <pmlopes> io.vertx.core.VertxException: Thread blocked

[12:14:22] <pmlopes> at io.vertx.core.http.impl.HttpClientRequestImpl.handleException(HttpClientRequestImpl.java:326)

[12:14:24] <pmlopes> at io.vertx.core.http.impl.ClientConnection.handleClosed(ClientConnection.java:307)

[12:14:26] <pmlopes> at io.vertx.core.net.impl.VertxHandler$$Lambda$28/1528776789.run(Unknown Source)

[12:14:27] <pmlopes> at io.vertx.core.impl.ContextImpl.lambda$wrapTask$3(ContextImpl.java:333)

[12:14:30] <pmlopes> at io.vertx.core.impl.ContextImpl$$Lambda$12/1908698042.run(Unknown Source)

[12:14:32] <pmlopes> at io.vertx.core.impl.ContextImpl.executeFromIO(ContextImpl.java:225)

[12:14:33] <pmlopes> at io.vertx.core.net.impl.VertxHandler.channelInactive(VertxHandler.java:99)

[12:14:36] <pmlopes> at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:208)

[12:14:38] <pmlopes> at io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:194)

[12:14:40] <pmlopes> at io.netty.handler.codec.ByteToMessageDecoder.channelInactive(ByteToMessageDecoder.java:306)

[12:14:42] <pmlopes> at io.netty.handler.codec.http.HttpClientCodec$Decoder.channelInactive(HttpClientCodec.java:212)

[12:14:44] <pmlopes> at io.netty.channel.CombinedChannelDuplexHandler.channelInactive(CombinedChannelDuplexHandler.java:132)

[12:14:45] <pmlopes> at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:208)

[12:14:48] <pmlopes> at io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:194)

[12:14:49] <pmlopes> at io.netty.channel.DefaultChannelPipeline.fireChannelInactive(DefaultChannelPipeline.java:828)

[12:14:52] <pmlopes> at io.netty.channel.AbstractChannel$AbstractUnsafe$7.run(AbstractChannel.java:621)

[12:14:54] <pmlopes> at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:358)

[12:14:56] <pmlopes> at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357)

[12:14:57] <pmlopes> at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112)

[12:15:00] <pmlopes> at java.lang.Thread.run(Thread.java:745)

[12:15:02] <pmlopes> and the it stays there for 30 minutes printing the same exception

[12:17:02] <purplefox> get a stack dump

[12:17:07] <purplefox> it might be a deadlock

[13:06:43] <purplefox> temporalfox: another EventBusMetrics question:

[13:06:44] <purplefox> void handlerUnregistered(H handler);

[13:07:19] <purplefox> What is the argument passed in here? It appears to be untyped

[13:09:52] <temporalfox> the argument is the object returned by handlerRegistered, which is a callback object of the implementation

[13:14:05] <purplefox> why does the metrics need to know that?

[13:31:29] <temporalfox> because it makes the SPI implementation typed and avoid casts

[13:31:59] <temporalfox> for instance

[13:32:00] <temporalfox> https://github.com/vert-x3/vertx-dropwizard-metrics/blob/master/src/main/java/io/vertx/ext/dropwizard/impl/EventBusMetricsImpl.java

[13:32:17] <temporalfox> public void handlerUnregistered(HandlerMetric handler) {

[15:26:48] <melvinross> is there anyway to use npm modules with js vertx in conjunction with maven?

[15:42:19] <melvinross> or just through regular vertx run?

[15:43:32] <pmlopes> @melvinross you can use npm modules with maven at least like this: https://mrhanlon.com/posts/using-npm-bower-and-grunt-with-maven/

[15:43:56] <pmlopes> or if your code is just javascript you can just use npm

[15:45:21] <pmlopes> http://vertx.io/blog/vert-x3-says-hello-to-npm-users/

[15:49:43] <melvinross> yeah, i was just trying to avoid it since it means adding nodejs as a deployment dependency

[15:50:38] <melvinross> i wonder how that maven solution will work with creating fat jars

[15:51:46] <cescoffier> melvinross: what kind of npm modules do you want to use ?

[15:52:16] <cescoffier> melvinross: if you just want to resolve them and embed them in a fat jat, you can use the frontend-maven-plugin

[15:52:35] <cescoffier> melvinross: this plugin installs node locally, and is able to resolve npm modules

[15:52:47] <cescoffier> (it can also call grunt, bower or gulp)

[15:53:05] <melvinross> at the moment, the elastic search module. i may just write an async http client

[15:53:53] <cescoffier> you can do it using the front-maven-plugin then.

[15:54:04] <cescoffier> sorry: frontend-maven-plugin

[15:54:15] <cescoffier> https://github.com/eirslett/frontend-maven-plugin

[15:55:13] <cescoffier> you configure it to retrieve node and npm, and then a second execution to resolve your npm

[15:55:30] <cescoffier> if you place them in the right directory, it should work smoothly

[15:56:06] <melvinross> thanks for the suggestions

[15:56:11] <alvaro_sanchez> purplefox: I will be pushing code for my talk [unknown:ldquo]Vert.x vs Ratpack[unknown:rdquo] in this repo: https://github.com/alvarosanchez/vertx-vs-ratpack

[15:56:28] <alvaro_sanchez> any feedback will be appreciated :)

[16:03:22] <cescoffier> alvaro_sanchez: how are you starting the vert.x app ?

[16:04:15] <alvaro_sanchez> at the moment I just have a hello world. I will create proper gradle-based applications in the following days

[16:08:04] <cescoffier> if you use a fat jar, you don't need the @Grab

[16:12:35] <alvaro_sanchez> yeah I know, I just wanted to have that running directly

[16:13:13] <alvaro_sanchez> making a JAR doesn't prove the point for a hello world (ie: it's an additional step)

[16:15:39] <alvaro_sanchez> I just created that repo, and the hello worlds are just the first step

[16:15:57] <alvaro_sanchez> but my goal is to write a simple REST API in both techs

[16:16:38] <alvaro_sanchez> and they'll be proper gradle-based projects, thus no more Grab's

[16:17:30] <cescoffier> cool

[16:17:35] <cescoffier> will follow ti

[16:18:26] <alvaro_sanchez> thanks!

[16:54:56] <melvinross> cescoffier: thanks for the help. it ended up being a bit of a bust, it can load the module, but fails on relative loads from the module itself, but it was a good exercise [16:55:47] <cescoffier> you embed all the modules in the fat jar ? [16:55:57] <melvinross> yeah

[16:56:29] <melvinross> the files definitely in there. can see it in file-roller [16:57:26] <cescoffier> oh I see, one of the NPM modules is calling 'requires' [16:57:34] <melvinross> yep

[16:57:39] <cescoffier> we may not support this case yet

[16:57:47] <cescoffier> as it's our own 'requires'

[16:59:01] <melvinross__> in case you were wondering, the easiest way i found to get the node modules into the fat jar via shader was to change the workingDirectory to being inside of src/js

[16:59:20] <cescoffier> pmlopes: are you around ?

[16:59:40] <cescoffier> Paulo knows much more things about node, so he may see the issue

[17:04:30] <jtruelove> temporalfox, big takeaways on hawkular?

[17:04:40] <temporalfox> jtruelove hi

[17:04:51] <temporalfox> actually we drawed a path toward inclusion in stack for 3.2

[17:05:04] <temporalfox> and we also discussed possiblity to have a single metrics project

[17:05:14] <temporalfox> containing dropwizard, hawkular in the future

[17:05:20] <jtruelove> interesting

[17:05:23] <temporalfox> and perhaps your work

[17:05:26] <temporalfox> to share things

[17:05:31] <temporalfox> like configuration option

[17:05:53] <jtruelove> yeah i put together vertx-bosun as well which is still pretty immature

[17:05:54] <temporalfox> for instance, in dropwizard it's possible to define which server URI are reported

[17:06:06] <temporalfox> so there is a Match Data Object

[17:06:14] <temporalfox> and hawkular plans to have something similar

[17:06:23] <temporalfox> would make sense to have something common with unified configuration

[17:06:45] <jtruelove> gotcha yeah opentsdb is very generic it's just a time series db that allows for tagging data points

[17:06:47] <temporalfox> in your case, I see hawkular reporting and opentsdb reporting having similar design with timer

[17:06:59] <temporalfox> would be possible to have somethign common

[17:07:11] <temporalfox> and just change the actual reporting

[17:07:20] <jtruelove> yeah i think i'll keep the verticle for listening right now and then everyone publishing to it

[17:07:28] <temporalfox> jtruelove ok

[17:07:42] <jtruelove> otherwise i'd have to elect one instance as 'the' consumer

[17:08:07] <temporalfox> I think in this case the actual reporter could be a straight client (using httpclient for instance)

[17:08:08] <jtruelove> which isn't the worst but it kinda of overloads one thread with all the reporting work + whatever else it's doing

[17:08:10] <temporalfox> or the event bus

[17:08:18] <temporalfox> it would not matter

[17:08:26] <temporalfox> the common stuff would just filter and collect metrics

[17:08:40] <temporalfox> and timely flush this to the actual TSDB

[17:08:51] <temporalfox> (for TSDB I mean hawkular or opentsdb or influx or…)

[17:08:59] <jtruelove> yeah and that works as long as you generically collect

[17:09:04] <temporalfox> there are many these days :-)

[17:09:08] <jtruelove> it's true

[17:09:20] <jtruelove> so that all the info you need is there when it hits the reporter

[17:09:28] <temporalfox> yes

[17:09:40] <temporalfox> I don't think we have time for this in 3.2

[17:09:48] <temporalfox> as thomas needs first to finish his stuff

[17:09:56] <temporalfox> and 3.2 is for end of novebmer

[17:10:15] <temporalfox> but after, I think consolidation is definitely interesting

[17:10:29] <temporalfox> (pretty much like vertx-auth consolidates Shiro, Mongo or Jdbc auth)

[17:25:46] <jtruelove> yeah and i'm more than happy to help out

[17:26:05] <jtruelove> first step is just wrapping up vertx-opentsdb so it can be used by SPI

[17:26:15] <jtruelove> as writing timing metrics in your code is a pain in the ass

[17:59:13] <jtruelove> temporalfox once you get the docs on how to integrate with vertx gen i can incorporate that stuff as right now i see the annotations but don't know where to start

[18:01:03] <jtruelove> have you seen the stuff we are doing with exovert at all? https://github.com/cyngn/exovert

[18:06:52] <temporalfox> jtruelove what do you expect from these docs exactly ?

[18:15:36] <jtruelove> just a walk through / tutorial on how to use and support the code generation features

[18:47:17] <temporalfox> so you mean for writing a polyglot API ?

[18:47:24] <temporalfox> jtruelove so you mean for writing a polyglot API ?

[18:48:21] <jtruelove> yeah more less

[18:48:27] <jtruelove> err or less

[18:48:49] <temporalfox> what is your goal ?

[18:48:56] <jtruelove> although as long as your library uses the event bus you can sorta get that anyway

[18:48:56] <temporalfox> I mean what would you do better with that ?

[18:49:19] <jtruelove> i guess if you want your library usable from any of the vertx languages you'd need that right?

[18:49:35] <temporalfox> what it buys is to have a polyglot API

[18:49:40] <temporalfox> so you have typed client

[18:49:48] <temporalfox> it can also use event bus with service proxies

[18:50:22] <temporalfox> so you have polyglot service proxies that invoke via event bus the underlying service

[18:50:50] <jtruelove> yeah that is what i was alluding to more or less with the event bus comment above

[18:50:59] <temporalfox> ok

[18:50:59] <temporalfox> the current guide talks more about the concept of codegen which are targetted from shim implementors

[18:51:06] <temporalfox> but it should / could be read by api designers

[18:51:17] <temporalfox> there should be a complementary guide for api authoring

[18:51:26] <temporalfox> that explains the setup

[18:51:36] <jtruelove> like so you want a niced typed metric publisher for any lang even though you deploy the consumer in java etc..

[18:52:01] <jtruelove> how you would get that is with the gen stuff it seems

[18:52:21] <jtruelove> granted they could look at the docs and see oh i can write my own i send to this topic with this message structure

[18:52:28] <jtruelove> it just lowers the barriers to use etc..

[21:13:10] *** ChanServ sets mode: +o purplefox