These are chat archives for miketheprogrammer/go-thrust

19th
Nov 2014
Michael Hernandez
@miketheprogrammer
Nov 19 2014 01:09
its starting out very simple, basically they breakdown is
  1. Web - parent package, contains anything needed to expose the underlying packages in a simple way (havent figured out what that might be, playing this as i go )
  2. Platform - contains the core js and the go file that has the registry methods, basically platform is a registry system, For instance it registers an object "Thrust" on the page and allows you do do neat things like Thrust.extend("rpc", rpcObject) and now you have Thrust.rpc
there are basic things there for dealing with webviews, and basic dom manipulation that will always get included, but the rest of it is more of a register what you need mentality
Shion Ryuu
@ShionRyuu
Nov 19 2014 02:57
func (tp ThrustProvisioner) Provision() error {
    Bootstrap()
    return nil
}
The function above should return Bootstrap() instead of nil
spawn.Run() should check the return value of cmd.Start()
Michael Hernandez
@miketheprogrammer
Nov 19 2014 03:29
Your correct @ShionRyuu
Done and pushed
Michael Hernandez
@miketheprogrammer
Nov 19 2014 04:00
Will fix spawn.Run soon
Michael Hernandez
@miketheprogrammer
Nov 19 2014 14:25
@ShionRyuu : spawn.Run now checks the value of cmd.Start, thank you
it logs and creates a panic if theres an error
Michael Hernandez
@miketheprogrammer
Nov 19 2014 14:37
@tehbilly if you have any time today, ill need your brain to bounce an idea off of
William McGann
@tehbilly
Nov 19 2014 15:05
Shoot. My last day on call, so it'll either be slow or hectic, but I'll be here more on than off.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 15:17
cool, so basically, when thinking about RPC from the browser to thrust, I started wondering how to get the responses back to the browser to let it know everything worked
right now the crazy asynchronous binding code i did doesnt really give you introspection into the results
Michael Hernandez
@miketheprogrammer
Nov 19 2014 15:39
For instance, how the hell does one know that menu.Create() succeeded or Window.Focus()
If we keep going with the current code, we might get too tightly coupled to it accross the many packages
I was thinking of creating a success channel
func (w *Window) Focus() responsechannel chan {
}
go
go
func (w *Window) Focus() responsechannel chan {
// make buffered channel here. 
// this will allow the user to block if they want, but not the binding to block
return responsechannel
}
William McGann
@tehbilly
Nov 19 2014 17:12
Hrm, you want the caller to block but not the dispatcher, yes? Have the caller pass in an unbuffered channel that the response is sent on.
And I wouldn't worry about naming your returns. But that's just personal preference, honestly.
Yeah, lucky me, today has been crazy so far, and I have no time to eat before a meeting I'm leading.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 17:21
Damn and no, i dont want the caller to block, i just mean, we should return channels so that the user can react to a response
Ideally the bindings will be used very little and sporadically, most of the time, it will be RPC among other things that are doing most of the active work
Gerred Dillon
@gerred
Nov 19 2014 17:34
I asked this a few days ago and then let this channel sort of get away from me - how do I call across the RPC bridge from both JS and Go? Couldn't find docs for it.
or do what you're saying above, expose a channel.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 17:37
@gerred im working on the RPC interface right now, there is no RPC yet.
Gerred Dillon
@gerred
Nov 19 2014 17:37
ok. I can help, is there an open issue?
Michael Hernandez
@miketheprogrammer
Nov 19 2014 17:37
we are trying to figure out the best way to expose RPC please se https://github.com/miketheprogrammer/go-thrust/tree/package/web_jsonrpc
lets open an issue as well
making ticket now
Gerred Dillon
@gerred
Nov 19 2014 17:40
I'm still not mentally sure if I feel more comfortable with a full RPC interface, or a channel on either side that I can listen for events on in JS
and select on from Go
I think in go-thrust proper I'd prefer the lower level construct, because you can build RPC on top of that as the user or make it a contrib.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 17:41
#28 miketheprogrammer/go-thrust#28
The lower level construct would be dispatcher.RegisterHandleFunc or dispatcher.RegisterHandler in the new PR for dispatcher enhancements with global events
basically
dispatcher.RegisterHandler(MYRPC)  // 
//where MYRPC is 
type MYRPC struct {
  Handle (commands.CommandResponse)
}
Gerred Dillon
@gerred
Nov 19 2014 17:44
yeah, that makes sense.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 17:44
then you can transform that commandresponse into whatever format you need for the frontend to respond
maybe even just json.Marshal(cr) and send that via something like birpc to the frontend
@gerred Do you not think I should provide at least a basic implementation for people to prototype off of
sorry I should say "we" because everyone in this channel has a vested interest
Gerred Dillon
@gerred
Nov 19 2014 17:48
i don't know, it's two approaches. By just providing the event bus primitive and exposing that event bus on both sides avoids having opinions in go-thrust on how RPC actually builds on top of that.
and then have an example RPC that's a really basic RPC build on top of that.
that's my personal preference, since it avoids opinion - all I want to do is ship JSON between go-thrust and thrust itself at the most basic level.
and what I do on top of that is where it starts to become different for every application
and it's easy then for people to release their thing, be it RPC, be it analytics, be it error reporting, etc.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 17:50
Yes, I believe so to, but I was also hoping to at least have a basic frontend interface, which would allow for the community to create modular packages that other people could use in their Go-Thrust applications
but maybe that is too much megalomania
Gerred Dillon
@gerred
Nov 19 2014 17:50
well
wouldn't a bidirectional event bus include a frontend interface?
ideally, the API around the bus would be powerful enough that an RPC could be built in a few lines of code.
like a really simple RPC.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 17:51
ah, i see what you mean
ok
Gerred Dillon
@gerred
Nov 19 2014 17:51
then I can decide if I need full RPC, or if I just need to ship JSON back and forth.
like for example, if I'm making a game, I may not want RPC - I may just want to ship input from the frontend into Go, and return back the next display state of the game.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 17:52
Thats actually a wonderful idea.
Lets come up with the most basic building blocks and build from there, the #1 thing always forgotten lol
Gerred Dillon
@gerred
Nov 19 2014 17:53
and then it's really easy from there, once I have an event channel that's simply JSON, to actually write an RPC on top of that.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 17:55
gotta eat real quick, then ill be back
Gerred Dillon
@gerred
Nov 19 2014 17:55
kk
thinking about the way I'd expect it to look on the JS side:
var channel = eventbus.forTopic('some-topic')
channel.on('data', function(data) { / ... / })
alternately
eventbus.on('some-topic:data', function(data) {})
Gerred Dillon
@gerred
Nov 19 2014 18:00
not sure which is better
or even just
eventbus.on('some-topic', function(data) {})
Gerred Dillon
@gerred
Nov 19 2014 18:07
and then have what you're talking about, a net/http-like HandleFunc
on the Go side.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 18:31
so there are different types of things to deal with
theres the general Thrust CommandResponse object
this object contains important information like the TargetID, for instance, which Window was the target of your action
It also contains two different sub structs ReplyResult, EventResult, these may or may not have data related to the response of your action
or related to an event being omitted
Michael Hernandez
@miketheprogrammer
Nov 19 2014 18:48
@gerred poke
// Mostly random psudo code to keep things simple these objects are most made up
WebSocket.New(function (rw ReadWriter) {
  dispatcher.RegisterHandleFunc(func(cr commands.CommandResponse) {
    rw.write(json.Marshal(commands.CommandResponse))
  })
  go func() {
    for {
      rw.Read()
    }
  }
})
Thrust.extend("bus", {
  _dispatcher: {
    registry: [],
    dispatch: function(commandresponse) {
      if ('string' === typeof commandresponse) {
        commandresponse = JSON.parse(commandresponse);
      }
      registry.forEach(function(handler) {
        if (handler.type == '*') {
           handler.handle(commandresponse);
           return;
        }
        if (handler.type == commandresponse._type) {
           handler.handle(commandresponse);
        }
      })
    }
  },
  registerByType: function (type, fn) {
    this._dispatcher.registry.push({
      type: type,
      handle: fn
    })
  },
  registerByTargetID: function (id, fn) {
    var matchFn = function (commandresponse) {
      if (commandresponse._target_id === id) {
        fn(commandresponse)
      }
    }
    this._dispatcher.registry.push({
      type: "*",
      handle: matchFn
    })
  }

})


Thrust.bus.registerByType("event", function (commandresponse) {

})

Thrust.bus.registerByType("reply", function (commandresponse) {

})

Thrust.bus.registerByType("invoke", function (commandresponse) {

})

Thrust.bus.registerByTargetID(1, function (commandresponse) {

})
Gerred Dillon
@gerred
Nov 19 2014 19:33
back
seems reasonable
Michael Hernandez
@miketheprogrammer
Nov 19 2014 19:35
more important than reasonable is it a step in a direction of something you would use
Gerred Dillon
@gerred
Nov 19 2014 19:38
i'm wondering if reply or invoke are necessary.
in the sense that is that a job for the bus or a library that builds on top of the bus.
outside of that
yeah, we're getting closer to something I'd for sure use.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 19:47
I supposed we can abstract the frontend out more, and simplify out, really all you need is a
Thrust.bus.on("message", function (commandresponse) {
   // are we an event
   // are we a reply
   // are we an invoke
})
// Or even rename commandresponse to just message
Gerred Dillon
@gerred
Nov 19 2014 19:51
yeah
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:15
btw, Thrust is basically any core stuff we feel is necessary
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:32
@gerred Important question, we want bi directional communication via this bus, write
right*
Gerred Dillon
@gerred
Nov 19 2014 20:33
yep
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:34
ok, so commandresponse wont do
Gerred Dillon
@gerred
Nov 19 2014 20:34
I would just have it be a piece of JSON, or already a JS object
send and receive on each side.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:35
yup
gotta figure out the best object to use.
Gerred Dillon
@gerred
Nov 19 2014 20:35
as far as structure goes?
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:40
yea
it needs to be able to mutate between several different struct types
as well as user addable struct types
type BusMessage struct {
    Type      string          `json:"type"`
    Value     json.RawMessage `json:"value"`
    Timestamp time.Time       `json:"timestamp"`
}
thinking that
where type is something like "Command", "CommandResponse"
Gerred Dillon
@gerred
Nov 19 2014 20:42
well would type even be a higher level thing. not much higher level.
but what I mean should BusMessage even have a Type
or
should you have a BusCommand Struct
that has Message BusMessage
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:43
Yes, because we need to know how to decode it
Gerred Dillon
@gerred
Nov 19 2014 20:44
hmm, alright.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:45
then we can have
type ValueDecoder interface {
    Decode() interface{}
}

// example

func (bm *BusMessage) Decode() interface{} {
    if cm.Type == "CommandResponse" {
        bm.Value = json.Unmarshal(&cm, commands.CommandResponse)
    }
}
does that seem idiomatic to you
Gerred Dillon
@gerred
Nov 19 2014 20:46
yeah, that looks good to me.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:47
ill also try to see if @tehbilly has anything to say about it when hes not so busy
its really hard making these decisions knowing that it will impact your users
Gerred Dillon
@gerred
Nov 19 2014 20:47
yeah
well fortunately the smaller this first pass is
the more it can be tweaked
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:48
yea
Gerred Dillon
@gerred
Nov 19 2014 20:48
before people build RPC on top of it
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:48
definitely
I like the idea of providing interfaces as well, sort of like how we added spawn.SetThrustProvisioner
so that the user is not stuck to the default behavior
William McGann
@tehbilly
Nov 19 2014 20:49
when he's not so busy
Riiiiight
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:49
lol
William McGann
@tehbilly
Nov 19 2014 20:49
Well let's see what I should be asked about!
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:50
Basically, building a basic Thrust.bus module instead of a whole rpc framework
William McGann
@tehbilly
Nov 19 2014 20:50
Talking about format of bus messages?
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:50
this is basically just a communication platform between the frontend and the backend
William McGann
@tehbilly
Nov 19 2014 20:50
I, for one, love bus style interfaces. Pubsub it up
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:51
we need a robust way to represent a message
ideally this would be so simple that the user could build pubsub on top of it.
William McGann
@tehbilly
Nov 19 2014 20:51
I think one single type of struct that defines a type, a timestamp, a unique ID is good. And then perhaps...
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:51
its really just a protocol for communicating
as well as the data right
as in my example
Value  json.RawMessage
William McGann
@tehbilly
Nov 19 2014 20:52
Yeah, but I was debating between a blob that could be decoded, simple data types, or perhaps an interface that could be encoded/decoded from json
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:52
interface turns into a map[string]interface
json.RawMessage is the proper way to decode an object based on information in the current json struct
so if your value is dependent on decoding other json first, then you embed a rawmessage
William McGann
@tehbilly
Nov 19 2014 20:54
Trying to think of whether there's a way to narrow the scope down a bit to make using it simpler (instead of having to encode/decode for every type) without losing flexibility. Can't think of anything offhand.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:54
yea its really hard
Gerred Dillon
@gerred
Nov 19 2014 20:54
so is there a way
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:55
even tv42/birpc needs a type
William McGann
@tehbilly
Nov 19 2014 20:55
I think starting with the raw, most flexible approach is the right way to do things.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:55
the type is the function call name
and the arguments to that call are json.RawMessage
Gerred Dillon
@gerred
Nov 19 2014 20:55
to do this pure WebSocket style - where literally what's being sent back and forth are strings.
and anything building on top of that
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:55
once he knows what the call is, he can then decode
Gerred Dillon
@gerred
Nov 19 2014 20:55
at all
has to handle for that.
William McGann
@tehbilly
Nov 19 2014 20:55
Why not []map[string]interface{}
For arguments.
Gerred Dillon
@gerred
Nov 19 2014 20:56
this should feel like on the client side like using websockets, it should be that low level.
enabling people to build the socket.io or sockjs or whatever on top of that.
(and that may even become a part of go-thrust, but not for this exact feature)
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:56
@gerred we can litterally do just that lol
Gerred Dillon
@gerred
Nov 19 2014 20:56
i think that's the base primitive.
William McGann
@tehbilly
Nov 19 2014 20:56
So you're wanting to use socket.io (for instance) on the app inside thrust, communicating with the go application on the backend.
Gerred Dillon
@gerred
Nov 19 2014 20:57
@tehbilly as an abstraction on top of the base communication primitive, yeah.
well
no, not actual websockets.
I'm talking more the level of the solution.
the messagebus being extremely low level.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:57
ah ok
William McGann
@tehbilly
Nov 19 2014 20:57
Here's a question, though. Why not? Do we need thrust to proxy that kind of complexity? Or do we want thrust to remain the interface handler alone?
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:58
cool i get it, basically "Close to the iron, but a lil` more sophisticated"
Gerred Dillon
@gerred
Nov 19 2014 20:58
so I'd have a library on top of it in the spirit of socket.io (not actually socket.io, but for this protocol)
William McGann
@tehbilly
Nov 19 2014 20:58
You're running go on the backend, a web app inside thrust, you can communicate with go over http
Gerred Dillon
@gerred
Nov 19 2014 20:58
and @tehbilly could have his own library on top of it in the spirit of sockjs
and someone else can build an RPC library.
I suppose that's true
it'd be nice if it were internal though.
William McGann
@tehbilly
Nov 19 2014 20:58
I think having thrust broker all of that would add complexity that really doesn't need to be there. But that's my initial knee-jerk reaction.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:58
@tehbilly My goal is to make it optional, its for users that want ease of prototyping
so they dont have to worry about certain complexities
Gerred Dillon
@gerred
Nov 19 2014 20:59
i mean, if I were to expose an HTTP server that I'd use in the client..
couldn't that cause firewall issues on the user end?
William McGann
@tehbilly
Nov 19 2014 20:59
Not in this case, since you're doing it locally.
Could even do it over a linux socket/named pipe
Gerred Dillon
@gerred
Nov 19 2014 20:59
ah true.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 20:59
ohhhh @gerred yea there will never be any actual bus
sorry for the confusion
it will always have to occur over actual websockets
Gerred Dillon
@gerred
Nov 19 2014 20:59
actually yeah that makes sense how else would it be done.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 21:00
The point is to write your app like a server
Gerred Dillon
@gerred
Nov 19 2014 21:00
well I guess you could hack deep into V8 like node-webkit did.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 21:00
yea, which is bad bad bad bad bad
William McGann
@tehbilly
Nov 19 2014 21:00
I think for flexibility and ease of use you could have thrust be the middleman to the extent that it provides information to the frontend about the backend, and so on
Gerred Dillon
@gerred
Nov 19 2014 21:00
yeah
OK that makes sense. for some reason I had some internal bus in my head.
well
if that's already provided.
William McGann
@tehbilly
Nov 19 2014 21:00
Then as you're writing your go app you can just view it in a browser if you need to, or use existing services that leverage http.
Sorry if I'm lagging behind, talking to my boss while chatting here :P
Gerred Dillon
@gerred
Nov 19 2014 21:01
all good
Michael Hernandez
@miketheprogrammer
Nov 19 2014 21:01
there will be a sort of internal bus, but that will be IPC between the Main document and Webviews
it will never touch Go-Thrust
Gerred Dillon
@gerred
Nov 19 2014 21:01
ok, so we already have the low level communication mechanism. :D
I RETRACT EVERYTHING.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 21:01
lol
William McGann
@tehbilly
Nov 19 2014 21:01
♪└(・。・)┐♪
Michael Hernandez
@miketheprogrammer
Nov 19 2014 21:02
Now, the point of any extra libraries in thrust would be just to simplify that process
and speed up prototyping
William McGann
@tehbilly
Nov 19 2014 21:02
See, I'm very biased though. I wanted to make sure I wasn't missing something.
Gerred Dillon
@gerred
Nov 19 2014 21:02
exactly.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 21:03
which is why we as the core devs have to decide, what is actually useful
William McGann
@tehbilly
Nov 19 2014 21:03
But what excited me most was the idea of taking a web application and just packing it up into a "standalone" app.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 21:03
and what can a user go get
yup
William McGann
@tehbilly
Nov 19 2014 21:03
And to Mike's credit, which he deserves a lot of, he's done a fantastic job and I've had very little input. Hooray for work work!
Michael Hernandez
@miketheprogrammer
Nov 19 2014 21:03
lol
William McGann
@tehbilly
Nov 19 2014 21:03
And I just ask questions and eff stuff up
Michael Hernandez
@miketheprogrammer
Nov 19 2014 21:04
so do i
William McGann
@tehbilly
Nov 19 2014 21:04
Do you?
Michael Hernandez
@miketheprogrammer
Nov 19 2014 21:04
but thats what programmers do eh, we eff shit up
yea, Im asking @spolu questions all the time
William McGann
@tehbilly
Nov 19 2014 21:04
Seriously, that's why today has been so busy. I'm bringing my entire team's applications' architecture around to something resembling modern.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 21:04
not really about go, but then again i ask tons of question in #go-nutes
William McGann
@tehbilly
Nov 19 2014 21:04
Y'know, being an oldhat gopher I should probably join there.
Lurking /r/golang is the worst I do anymore. And that's become less newbies discovering things together.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 21:09
@gerred If you really wanted, I could ask spolu to expose the Thrust stdout in a window document, but it probably wouldnt come down the pipe for quite some time
theres alot more important stuff to handle
and it would only be a one way things, just Thrust ==> window.{somenativemodulename}
William McGann
@tehbilly
Nov 19 2014 21:10
And if you were really clever you could expose an SSE endpoint for thrust's stdout in go
Michael Hernandez
@miketheprogrammer
Nov 19 2014 21:10
SSE?
William McGann
@tehbilly
Nov 19 2014 21:11
server-sent events. Think one-way websockets with better performance.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 21:11
ooooooo
i wanna do that lol
William McGann
@tehbilly
Nov 19 2014 21:12
lol, just pass each line from the spawned process' stdout into a buffered channel, have an SSE endpoint send a line and flush it for every message.
Which is actually quite easy on both parts. It's how I do realtime "log" viewing in one of my internal apps here.
Actually, wouldn't hurt to put a utility like that in later, to help debugging from the app's frontend. But that's there, not here.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 21:13
yea, its just an unclosed http connection
im reading about it now
@tehbilly We can add some really cool things, like a debug panel, that queries the expvar endpoint
so while you testing you application you can see expvar data
see, those are utilities that can help prototyping of applications
William McGann
@tehbilly
Nov 19 2014 21:15
Absolutely. Hrm.
Would make sense to not have those tied directly to the process, though. In case something forces a shutdown/etc. Perhaps a separate package/repo that exposes a regular ol' spa with debug data?
Open window in browser if you want to debug running instance.
Spitballing ideas here
Michael Hernandez
@miketheprogrammer
Nov 19 2014 21:18
Either should work, but for the people that really want to isolate debugging from the actually client application
thrust.NewWindow("http://localhost:myport/debug")
William McGann
@tehbilly
Nov 19 2014 21:18
Bam, flexible and powerful.
I friggin' dig it.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 21:19
now every time your application starts, 2 windows will popup, with with your app, and one with your actualy code
i mean one with your debug
lol
William McGann
@tehbilly
Nov 19 2014 21:19
Damnit, Mike, say what you mean!
Michael Hernandez
@miketheprogrammer
Nov 19 2014 21:19
im multitasking too too much
Im always doing 10 things at once
William McGann
@tehbilly
Nov 19 2014 21:26
Same here, unless I get a good hard dose of the orange dragon
Michael Hernandez
@miketheprogrammer
Nov 19 2014 21:29
ive heard you reference this orange dragon multiple times lol
is it a vape flavor?
William McGann
@tehbilly
Nov 19 2014 21:31
Adderall. Grab the tail and hold on.
Michael Hernandez
@miketheprogrammer
Nov 19 2014 21:35
ahh heh
used to be an adderall fiend, a long time ago
William McGann
@tehbilly
Nov 19 2014 22:13
Only way I can accomplish anything, really. My ADD is absolutely terrible.
Speaking of, time to go get the baby. Will try to get online in a bit. Gotta finish my architecture diagram.