[00:00] <niemeyer> fwereade_: The charm being upgraded to and the old charm are both in the same location
[00:01] <niemeyer> fwereade_: When we resolve, we read it to tell what's in there
[00:01] <niemeyer> fwereade_: If the user moved backwards, the metadata will have moved backwards with it
[00:01] <niemeyer> fwereade_: and juju will automatically put it back to work, and then upgrade it again if necessary
[00:07] <fwereade_> niemeyer, ok, yes, that makes sense... I'm going to have a lie down and a think about this for a bit, and if I'm lucky I won;t come back until tomorrow :)
[00:08] <niemeyer> fwereade_: I'll be wishing for the best :-)
[00:08] <niemeyer> fwereade_: Have a good night
[01:00] <niemeyer> davecheney: Heya
[01:01] <davecheney> niemeyer: howdy!
[01:01] <niemeyer> davecheney: Sorry for being a bit behind on your reviews.. I know you have some good stuff in there
[01:01] <davecheney> np, i know you have your hands full
[01:02] <davecheney> i've got pleanty of bugs (most that I have registered :) to keep me busy
[01:02] <davecheney> niemeyer: how is your transaction stuff going ?
[01:03] <niemeyer> davecheney: Pretty good.. working on it right now, finishing insert/remove
[01:03] <niemeyer> davecheney: The rest seems solid
[01:03] <davecheney> awesome
[02:04] <niemeyer> davecheney: What are you up to?
[02:05] <davecheney> niemeyer: working on the final part of https://bugs.launchpad.net/juju-core/+bug/1025656
[02:06] <niemeyer> davecheney: Neat
[02:06] <niemeyer> davecheney: Do you have plans for what to do after that?
[02:07] <davecheney> apart from fixing bugs, i'm looking to you and mark to provide direction
[02:08] <niemeyer> davecheney: Cool, I was wondering if you might appreciate working on being a bit of an integration champion for the next couple of months
[02:08] <davecheney> niemeyer: i would love that
[02:08] <niemeyer> davecheney: I appreciated a lot the stuff you've done in the sprint and after that to make it work for real
[02:08] <davecheney> aww shucks
[02:09] <niemeyer> davecheney: Having you actively looking for the missing pieces of the puzzle, and chasing down broken parts either directly or by poking people to fix stuff, will be invaluable
[02:10] <davecheney> speaking of that, i tried to run juju on arm yesterday
[02:10] <davecheney> with mixed results
[02:11] <davecheney> niemeyer: i heard you have a juju intergratino testing tool
[02:11] <davecheney> you were talking about that in the sprint
[02:11] <davecheney> would you like to hand that over ?
[02:11] <niemeyer> davecheney: I have a half baked functional test runner that I think we should revive, but it's nothing to sweat at
[02:12] <niemeyer> davecheney: lp:~juju/juju/ftests
[03:37] <niemeyer> Internal compiler error.. boom
[03:37] <niemeyer> Silly one, though
[07:10] <rogpeppe> mornin' all
[07:30] <TheMue> morning
[07:36] <rogpeppe> TheMue: hiya
[07:36] <TheMue> rogpeppe: hi, how has your free day been?
[07:37] <rogpeppe> TheMue: good thanks. it was our first wedding anniversary - we went for a nice walk and for a meal at a nice restaurant.
[07:38] <TheMue> rogpeppe: oh, congratulations
[07:38] <TheMue> rogpeppe: we'll have our silver anniversery in two years ;)
[07:38] <rogpeppe> TheMue: i see the release meeting was postponed to today, so i didn't miss anything, right?
[07:38] <rogpeppe> TheMue: wow!
[07:39] <TheMue> rogpeppe: yep, yesterday no meeting, and mark felt ill
[07:59] <davecheney> rogpeppe: he had been at PyCon
[07:59] <rogpeppe> davecheney: ah, *that* sort of ill :-)
[07:59] <davecheney> and you remember that story he told us at that Bar across the road from the Pirate Cafe in Lisbon ?
[07:59] <rogpeppe> davecheney: mornin' BTW!
[07:59] <davecheney> that might have been related
[08:00] <davecheney> rogpeppe: yes hello
[08:00] <davecheney> i'm just about to sign off for a bit, gotta get the dinner on
[08:00] <rogpeppe> davecheney: k
[08:00] <rogpeppe> davecheney: enjoy - see you for the meeting in a little bit
[09:35] <Aram> moin.
[09:38] <TheMue> Aram: moin
[09:39] <TheMue> so, merged trunk into my three open branches, now start a new one
[09:46] <TheMue> Aram: regarding life, when calling State.RemoveMachine() you set the state of the machine to Dying. how do you remove a machine? IMHO one should Kill() and later Die() a machine before RemoveMachine() is checking that it's dead and then removes the machine from the state.
[09:47] <Aram> I don't understand the question, yes, you should call Kill + Die (or just die, alive -> die is valid now) before calling RemoveMachine.
[09:47] <Aram> is this not so?
[09:47] <TheMue> Aram: not in trunk
[09:48] <TheMue> Aram: here RemoveMachine() in mstate searches the machine with life = Alive and sets it to Dying
[09:48] <Aram> ?!?
[09:48] <Aram> let me take a look
[09:49] <Aram> aaah
[09:49] <Aram> yes
[09:49] <Aram> removemachine
[09:49] <TheMue> state line 71ff
[09:49] <Aram> for some stupid reason I though you were talking about RemoveRelation.
[09:49] <Aram> yes, lifecycle for relation is not done yet.
[09:49] <Aram> erm
[09:49] <TheMue> Aram: hehe, no
[09:49] <Aram> for machine
[09:49] <Aram> only relations have full lifecycle in mstate ATM.
[09:50] <TheMue> Aram: ah, ok, so i'm still right with our Kill() -> Die() agreement
[09:50] <Aram> yes.
[09:50] <TheMue> *pheeew*
[09:50] <TheMue> +1
[09:50] <Aram> in fact, lifecycle for machines is what I should do right now, after I push confignodes.
[09:52] <TheMue> Aram: i only stumbled about it when doing a cross-check. sate has lifecycle now for relations as well as a life watcher and a service relation watcher (all in the review queue) and today i'm starting with units
[09:52] <Aram> why units before machines?
[09:53] <Aram> or are you talking about the unit watcher?
[09:54] <TheMue> Aram: i'm going bottom up, as discussed with niemeyer. relations, units, services, machines
[09:54] <TheMue> Aram: before you free a machine everything else has to be done
[10:18] <TheMue> Aram: another question. Relations() of Service returns only alive relations in mstate. i thought we always return all, individual life state can then be retrieved with Relation.Life()
[10:19] <Aram> you're right, I haven't done that yet because I didn't want to modify the tests.
[10:19] <Aram> (yet).
[10:24] <TheMue> Aram: ok
[10:24] <Aram> btw, confignodes were beautiful.
[10:24] <Aram> the implementation is really nice.
[10:25] <Aram> it takes advantage of the dynamic, schemaless nature of mongodb.
[10:30] <TheMue> Aram: i'm pretty sure that it will be more elegant than the zk counterpart
[10:56] <Aram> meeting in 4 minutes?
[10:56] <davecheney> yy
[10:57] <Aram> I'll be late ~10 minutes, start without me.
[10:58] <davecheney> mate, we'll all be late
[10:58] <davecheney> ain't no mramm yet
[10:58] <Aram> hhe.
[10:58] <davecheney> nor niemeyer
[11:01] <TheMue> davecheney: not yet awakened
[11:03] <niemeyer> Goooood morning!
[11:03] <davecheney> heeeelo
[11:04] <TheMue> niemeyer: heeeeeeya
[11:04] <niemeyer> Is it party time?
[11:04] <TheMue> niemeyer: indeed, but mramm is not yet here
[11:04] <niemeyer> Okay, I'm sending invites then
[11:04] <rogpeppe> niemeyer: seems to be.
[11:05] <niemeyer> rogpeppe: Hey!
[11:05] <niemeyer> rogpeppe: Welcome back
[11:07] <rogpeppe>  fwereade__: ping
[11:07] <fwereade__> rogpeppe, pong
[11:08] <rogpeppe> fwereade__: meeting time...
[11:08] <fwereade__> rogpeppe, oh, so it is :)
[11:08] <davecheney> mramm is in my time zone
[11:08] <davecheney> should I call him ?
[11:08] <rogpeppe> davecheney: good plan
[11:08] <davecheney> imma skype him
[11:08] <rogpeppe> davecheney: youa doa thata
[11:09] <niemeyer> Aram: ping?
[11:16] <Aram> sorry for being late guys
[11:16] <Aram> had an emergency
[11:45] <davecheney> are we all also going to UDS ?
[11:45] <davecheney> I only have an invite for the pre UDS kegger
[11:49] <davecheney> and that was all anyone wrote
[12:04] <mramm> https://bugs.launchpad.net/juju-core/+bug/1028437
[12:12] <mramm> https://launchpad.net/juju-core/+milestone/1.3
[12:43] <mramm> thanks again everybody!
[12:44] <mramm> I know that putting those two meetings together made it very long
[12:45] <rogpeppe> anyone fancy having a chat about the design of the upgrade command?
[12:45] <rogpeppe> niemeyer, fwereade__, davecheney: ^ ?
[12:46] <fwereade__> rogpeppe, a little focused elsewhere atm but I'll try to keep half an eye on one if it happens :)
[12:46] <rogpeppe> fwereade__: ta
[12:49] <rogpeppe> niemeyer: does this LGTY, or had you just not finished the complete review yet? https://codereview.appspot.com/6463057/
[12:50] <niemeyer> rogpeppe: I'm just grabbing some chimarrão..
[12:50] <rogpeppe> niemeyer: nop
[12:50] <rogpeppe> np
[12:51] <davecheney> night lads, pumpkin time
[12:56] <mramm> night all
[12:57] <niemeyer> rogpeppe: I haven't reviewed it after you fixed.. will check it out again now
[12:57] <rogpeppe> niemeyer: thanks
[12:58] <niemeyer> rogpeppe: Well, and you fixed it 2h ago.. so that's not too surprising :-)
[12:58] <rogpeppe> niemeyer: np. it just seemed like there might have been some more substantial comments waiting in the wings. i'm glad that there aren't!
[12:59] <niemeyer> rogpeppe: Ah, cool, that was mainly it really
[13:00] <niemeyer> rogpeppe: LGTM, thanks!
[13:00] <rogpeppe> niemeyer: lovely, thanks a lot
[13:00] <rogpeppe> niemeyer: any chance we could have a brief discussion about the juju upgrade command?
[13:01] <rogpeppe> niemeyer: because that's what i'm doing next, i think.
[13:03] <niemeyer> rogpeppe: Of course
[13:03] <niemeyer> rogpeppe: Let's go
[13:04] <rogpeppe> niemeyer: i've been wondering about two commands
[13:04] <rogpeppe> niemeyer: juju upload-tools and juju upgrade
[13:05] <rogpeppe> niemeyer: and i've been wondering how the flags to upgrade might work (if we decide to provide some capability to upgrade at finer granularity than "everything all at once")
[13:05] <niemeyer> rogpeppe: We already have an --upload-tools flag in bootstrap.. what about upgrade --upload-tools?
[13:05] <rogpeppe> niemeyer: the thing is that upload-tools is useful independently of upgrade
[13:06] <rogpeppe> niemeyer: (for instance if you want to make tools for several different platforms available)
[13:06] <niemeyer> rogpeppe: The only moment I can foresee upload-tools being used independently is to build the public bucket
[13:07] <niemeyer> rogpeppe: Otherwise, there's nothing wrong with doing upgrade --upload-tools on the different platform too
[13:07] <rogpeppe> niemeyer: because nobody will ever do cross-platform stuff with a development version?
[13:07] <niemeyer> rogpeppe: I'm sure Dave will :-)
[13:08] <niemeyer> rogpeppe: upgrade --upload-tools should work
[13:08] <rogpeppe> niemeyer: hmm, i suppose it doesn't really matter that we'll get half the upgrade done first, then half later.
[13:08] <niemeyer> rogpeppe: Right
[13:08] <rogpeppe> niemeyer: but i was thinking about building the public bucket too
[13:08] <niemeyer> rogpeppe: Yeah, for that it may be useful, but the semantics may be different.. we don't need an environment running for that
[13:09] <rogpeppe> niemeyer: true.
[13:10] <niemeyer> rogpeppe: So I suggest getting --upload-tools working first, since that gets us going development wise..
[13:10] <niemeyer> rogpeppe: The command should probably be called "upgrade-juju", btw
[13:10] <rogpeppe> niemeyer: ok. what about --version? do we allow the specification of a desired version or  not?
[13:10] <rogpeppe> niemeyer: +1
[13:10] <niemeyer> rogpeppe: To avoid the ambiguity with upgrading charms
[13:11] <niemeyer> rogpeppe: Not for now, at least
[13:11] <rogpeppe> niemeyer: and another thing: it would be nice to support this workflow: change source; juju-upgrade; test; change source; juju-upgrade; test
[13:12] <TheMue> niemeyer: if i scanned the code right the ServiceUnitWatcher is not been used today. where will it be used later?
[13:12] <rogpeppe> niemeyer: but we won't be able to do that unless the version number changes each time.
[13:12] <rogpeppe> niemeyer: so i was wondering about --bump-version or something like that.
[13:13] <niemeyer> rogpeppe: Yeah, sounds nice to have something like this.. I wonder about the details, though
[13:13] <rogpeppe> niemeyer: which would force to version to be one more than the current max version available in the private storage.
[13:13] <niemeyer> rogpeppe: Ah, ok, without touching the local version
[13:13] <rogpeppe> niemeyer: yeah
[13:13] <niemeyer> rogpeppe: Sounds sensible
[13:14] <niemeyer> TheMue: There were a bunch of things that were going to use it.. watching upgrade flags, watching agent version, ...
[13:14] <niemeyer> TheMue: Funny enough, they both were moved in different directions
[13:15] <TheMue> niemeyer: ic
[13:16] <rogpeppe> niemeyer: i had some thoughts about major-version upgrades too, but i think they can wait
[13:16] <niemeyer> rogpeppe: +1
[13:16] <TheMue> niemeyer: just ask because of lifecycle
[13:16] <niemeyer> fwereade__: Do we have any need for the unit watcher nowadays in the uniter?
[13:16] <TheMue> niemeyer: the watcher has to be changed to deliver alive, dying and dead units
[13:16] <rogpeppe> niemeyer: so for now, here's the plan: juju upgrade-juju [--upload-tools] [--bump-version]
[13:16] <niemeyer> fwereade__: Or anything you can foresee?
[13:17] <niemeyer> rogpeppe: +1!
[13:17] <rogpeppe> niemeyer: cool, will do
[13:17] <fwereade__> niemeyer, what TheMue said, I think
[13:17] <niemeyer> rogpeppe: So neat
[13:17] <fwereade__> niemeyer, it will want to know when it's Dying/Dead
[13:18] <niemeyer> fwereade__: Ah, of course
[13:18] <niemeyer> TheMue: ^
[13:18] <TheMue> fwereade__: yes
[13:18] <TheMue> fwereade__: so if we'll have a user of the watcher once it's worse change it (like the service relation watcher)
[13:19] <TheMue> fwereade__: but today it's unused ;)
[13:19] <fwereade__> TheMue, +1
[13:22] <rogpeppe> niemeyer: one other little twist occurs to me: the upgrade-juju command will need to know the series and architecture of the machine that each agent is running on. i'm *thinking* that it will find this out by looking at the agent's proposed tools (which should be set before the agent is assigned to a machine). does that sound reasonable?
[13:22] <niemeyer> TheMue: If we do the mstate migration fast enough we don't have to worry about that in state
[13:23] <niemeyer> rogpeppe: Yeah, sounds like a reasonable way forward
[13:24] <niemeyer> rogpeppe: We'll need constraint support in the near future, but we're not there yet, and it's not clear it'd be any better either way
[13:24] <TheMue> niemeyer: ok, so i'll stop here now and continue with mstate after lunch ;)
[13:25] <rogpeppe> niemeyer: yeah, i think that when we *do* have constraints, the proposed agent tools will still encapsulate the solved constraint in exactly the way that the tools require, so won't need changing.
[13:25] <TheMue> lunchtime (today a bit later)
[13:26] <niemeyer> TheMue: Please synchronize carefully with Aram
[13:27] <niemeyer> TheMue: It's easy to parallelize, and it's also very easy to step on each other's toes
[13:27] <niemeyer> rogpeppe: Agreed
[13:27] <niemeyer> TheMue: Enjoy
[13:27] <rogpeppe> niemeyer: great.
[13:38] <fwereade__> niemeyer, https://codereview.appspot.com/6441169
[13:44] <niemeyer> fwereade__: looking
[13:44] <fwereade__> niemeyer, when you're done, I think I also need to talk about upgrades a bit more, I'll go make a sandwich and try to marshal my thoughts
[13:45] <niemeyer> fwereade__: Done
[13:46] <niemeyer> fwereade__: It looks good, but my first impression is that it could be a lot slimmer with a config node and no new ServiceCharm type
[13:48] <niemeyer> fwereade__: Pretty much: 1) read config node; 2) return value a value b
[13:48] <fwereade__> niemeyer, hm, maybe -- but the watcher needs a single type to return
[13:48] <fwereade__> niemeyer, and, honestly, the fiddling around with types seems to cost as many lines as just doing it with a serviceNode does
[13:48] <niemeyer> fwereade__: ServiceCharmChange..
[13:49] <fwereade__> niemeyer, yeah, fair enough
[13:49] <niemeyer> fwereade__: I don't get your comment regarding fiddling with types
[13:49] <niemeyer> fwereade__: There's a lot of logic there that can go away entirely
[13:49] <fwereade__> niemeyer, casting stuff to strings/bools, dealing with what happens if they're not right
[13:50] <niemeyer> fwereade__: Well, just don't.. that's what you're doing now
[13:50] <fwereade__> niemeyer, you mean the retryChange on the serviceNode? that's only there because I thought you'd prefer it in case we added more fields
[13:50] <fwereade__> niemeyer, what, just panic if I get rubbish in the node?
[13:50] <niemeyer> fwereade__: Using such a type is no different than doing "v, _ := i.(bool)"
[13:51] <fwereade__> niemeyer, yeah, I guess, it just seemed like ConfigNode was overkill for two totally predictable fields
[13:52] <fwereade__> niemeyer, anyway, happy to do it as you suggest
[13:52] <niemeyer> fwereade__: I'd agree if we weren't doing non-fun stuff by hand as an alternative
[13:53] <fwereade__> niemeyer, heh, the confignode seemed to me like the unfun way there
[13:53] <fwereade__> niemeyer, anyway sgtm
[13:53]  * fwereade__ remembers why he'd put the toaster away in the cupboard in the first place, you need to watch the damn thing like a hawk :/
[13:54] <niemeyer> fwereade__: Unfun as in significantly more logic, in exchange for ... ?
[13:54] <niemeyer> fwereade__: I may be on crack
[13:54] <niemeyer> fwereade__: Let's see how it looks like
[13:59] <fwereade__> niemeyer, it'll probably actually trun out better, your instincts are usually solid :0
[14:01] <niemeyer> fwereade__: Cheers! :)
[14:28] <fwereade__> niemeyer, ok, should be ready to propose again in a mo, but I think I need another chat about charm upgrade errors
[14:29] <fwereade__> niemeyer, so, when we get an error, it's because there was a conflict trying to pull into the charm tree from the charms repo
[14:30] <niemeyer> fwereade__: Right
[14:31] <fwereade__> niemeyer, but I'm still not sure about how we handle it -- what does juju resolved imply here?
[14:32] <fwereade__> niemeyer, ISTM that it just means the user has done *something*, and they might themselves have updated the charm to the desired version and they might have reverted and made some more changes that should allow the upgrade to go ahead
[14:32] <niemeyer> fwereade__: We could make it do "bzr resolved --all + bzr commit -m ..."
[14:33] <fwereade__> niemeyer, and then we just try to pull again, which might do nothing or might upgrade successfully or might cause a new error
[14:33] <fwereade__> ?
[14:33] <fwereade__> niemeyer, and from that operation we determine what the new state of the charm really is?
[14:34] <niemeyer> fwereade__: I think we can just allow the charm to run again if the operation succeeds
[14:34] <niemeyer> fwereade__: Oh, wait.. we can't
[14:35] <niemeyer> fwereade__: Because we need to take a decision regarding whether to run the hook or not
[14:35] <fwereade__> niemeyer, ok, and the success is what determines what the version is? oh, bother
[14:35] <fwereade__> niemeyer, ah ok, yeah, that should be easy though
[14:36] <niemeyer> fwereade__: Yeah, I was just thinking that we could put the charm back in normal working mode and allow it to re-run the upgrade, but we can't.. we really have to take a decision right there if the upgrade is happening or not
[14:36] <fwereade__> niemeyer, yeah, I think that once we've started upgrading we shouldn't stop until we succeed
[14:37] <niemeyer> fwereade__: Allowing for a rollback also seems fine.. if diskVersion == oldVersion { abort upgrade and restart normally }
[14:39] <fwereade__> niemeyer, sorry, I'm not following
[14:39] <fwereade__> niemeyer, what causes us to do that?
[14:39] <niemeyer> fwereade__: We're saving the charm version within the bzr branch we use to prepare the upgrade, right?
[14:40] <fwereade__> niemeyer, perhaps; but where exactly?
[14:41] <fwereade__> niemeyer, and can we depend on that if it's something the user has access to?
[14:41] <niemeyer> fwereade__: I assumed it would be part of the charm directory itself.. we talked about unit.SetCharm(charm) when the unit is running, to report the version actually in use, right?
[14:41] <fwereade__> niemeyer, the second part, yes
[14:41] <niemeyer> fwereade__: Well, the user has access to the kernel of the machine too :-)
[14:42] <fwereade__> niemeyer, sure, but we aren't telling the user "hey, go and fix the kernel"
[14:42] <niemeyer> fwereade__: This is metadata that should be in a dot file of some sort within the charm directory.. if the user hacks that manually, good luck :)
[14:43] <niemeyer> fwereade__: Are we not? If the kernel breaks, we definitely say that
[14:43] <fwereade__> niemeyer, my instinct says that we should be storing it somewhere outside the charm directory and updating it based on our knowledge of the success of change operations, just as I expected we would the installing/upgrading/installed state of the charm
[14:44] <niemeyer> fwereade__: I don't get the contention in this bit.. you're saving the whole charm and snapshotting it.. how come it feels bad to save the version being snapshotted with it?
[14:46] <fwereade__> niemeyer, I'm not entirely sure it does, I just was expecting to leave the charm directory as the user's playground as much as possible
[14:47] <fwereade__> niemeyer, and to keep the state we depend upon separate
[14:47] <fwereade__> niemeyer, but I'm pretty comfortable either way
[14:48] <niemeyer> fwereade__: I think it's fine to have the state, as in, what's going on with the charm, somewhere else
[14:49] <niemeyer> fwereade__: But being able to tell what charm version is that thing we're looking at feels very convenient
[14:49] <niemeyer> fwereade__: It's much more likely that a version being snapshotted with the content will be right than something we keep ourselves independently
[14:50] <niemeyer> fwereade__: Otherwise, "bzr revert".. boom.. state is wrong
[14:50] <fwereade__> niemeyer, ok, that seems good then
[14:51] <fwereade__> niemeyer, so external state controls how we interpret internal state
[14:51] <niemeyer> fwereade__: Right.. external state tells what we've been doing about it.. internal state simply says what it is ATM
[14:51] <niemeyer> fwereade__: Well.. version really.. let's avoid one more "state" :-)
[14:53] <fwereade__> niemeyer, ok, I have some lurking uncertainty but I won't know what is is or whether it's real until I've implemented a bit more :)
[14:53] <niemeyer> fwereade__: I can sympathize
[14:54] <fwereade__> niemeyer, anyway, reproposed https://codereview.appspot.com/6441169 :)
[14:55] <niemeyer> fwereade__: How did it feel?
[14:55] <fwereade__> niemeyer, just as good -- not convinced it's really better but I don;t think it's any worse :)
[14:56] <fwereade__> niemeyer, it probably did get a little smaller though, I didn't count
[14:57] <niemeyer> fwereade__: Yeah, a few types/functions/closures less, thanks
[15:07] <niemeyer> fwereade__: Reviewed
[15:08] <niemeyer> fwereade__: Glad to see 100 lines going away
[15:08] <fwereade__> niemeyer, yeah, always nice :)
[15:08] <fwereade__> niemeyer, thanks
[15:09] <fwereade__> niemeyer, all looks sound
[16:34] <niemeyer> Lunch
[18:23] <rogpeppe> fwereade_: ping
[19:45] <niemeyer> Somewhat of a quiet day..
[20:13] <rogpeppe> niemeyer: i hope to remedy that tomorrow, but i'm off now....
[20:13] <rogpeppe> niemeyer: see you tomorrow
[20:13] <niemeyer> rogpeppe: A calm day is good every once in a while..
[20:13] <niemeyer> rogpeppe: Have a good time!