protocol

protocol

    _self = this

    if console?.log?
     LOG = console.log.bind console
    else
     LOG = -> null

    if console?.error?
     ERROR_LOG = console.error.bind console
    else
     ERROR_LOG = -> null

    POLL_TYPE =
     progress: true

##Response class

    class Response
     constructor: (data, port, options) ->
      @id = data.id
      @port = port
      @options = options
      @queue = []
      @fresh = true

     progress: (progress, data, callback) ->
      @queue.push
       method: 'progress'
       data: data
       options: {progress: progress}
       callback: callback
      @_handleQueue()

     success: (data) ->
      @queue.push method: 'success', data: data, options: {}
      @_handleQueue()

     fail: (data) ->
      @queue.push method: 'fail', data: data, options: {}
      @_handleQueue()

     setOptions: (options) ->
      @options = options
      @fresh = true
      @_handleQueue()

     _handleQueue: ->
      return unless @queue.length > 0

      d = @queue[0]

      if @port.isStreaming
       @port.respond this, d.method, d.data, d.options, @options, d.callback
       @queue.shift()
      else if @fresh
       @port.respond this, d.method, d.data, d.options, @options, d.callback
       @queue.shift()
       @fresh = false

##Call class

    class Call
     constructor: (@id, @method, @data, @callbacks, @options) -> null

     handle: (data, options) ->
      if not @callbacks[options.status]?
       return if options.status is 'progress'
       #Handled by caller
       throw new Error "No callback registered #{@method} #{options.status}"
      self = this
      setTimeout (-> self.callbacks[options.status] data, options), 0

      if POLL_TYPE[options.status]?
       return false
      else
       return true

##Port base class

    class Port
     constructor: ->
      @handlers = {}
      @callsCache = {}
      @callsCounter = 0
      @id = parseInt Math.random() * 1000
      @responses = {}
      @wrappers =
       send: []
       respond: []
       handleCall: []
       handleResponse: []

     isStreaming: true

     onCallError: (msg, options) ->
      for id, call of @callsCache
       if not call.callbacks.fail?
        ERROR_LOG 'fail callback not registered', call.method, call.data
       else
        call.callbacks.fail error: 'connectionError', msg: msg, options: options, {}

      @callsCache = {}

      @errorCallback msg, options

     onHandleError: (msg, data, options) ->
      @errorCallback msg, data
      response = new Response data, this, options
      response.fail msg

     errorCallback: (msg, options) ->
      ERROR_LOG msg, options

     wrap: (wrapper) ->
      for key, f of wrapper
       if @wrappers[key]?
        @wrappers[key].push f
       else
        this[key] = f

###Send RPC call

     send: (method, data, callbacks, options = {}) ->
      if (typeof callbacks) is 'function'
       callbacks =
        success: callbacks

      for f in @wrappers.send
       return unless f.apply this, [method, data, callbacks, options]

      params = @_createCall method, data, callbacks, options
      @_send params, callbacks

###Respond to a RPC call

     respond: (response, status, data, options = {}, portOptions = {}, callback = null) ->
      for f in @wrappers.respond
       return unless f.apply this, [response, status, data, options, portOptions]

      @_respond (@_createResponse response, status, data, options), portOptions, callback
      if not POLL_TYPE[status]?
       delete @responses[response.id]

###Create Call object
This is a private function

     _createCall: (method, data, callbacks, options) ->
      call = new Call "#{@id}-#{@callsCounter}", method, data, callbacks, options
      @callsCounter++
      @callsCache[call.id] = call

      params =
       type: 'call'
       id: call.id
       method: call.method
       data: call.data

      params[k] = v for k, v of options
      return params

###Create Response object

     _createResponse: (response, status, data, options) ->
      params =
       type: 'response'
       id: response.id
       status: status
       data: data

      params[k] = v for k, v of options

      return params

###Add handler

     on: (method, callback) ->
      @handlers[method] = callback

###Handle incoming message

     _handleMessage: (data, options) ->
      switch data.type
       when 'response'
        @_handleResponse data, options
       when 'call'
        @_handleCall data, options
       when 'poll'
        @_handlePoll data, options

     _handleCall: (data, options) ->
      for f in @wrappers.handleCall
       return unless f.apply this, arguments
      if not @handlers[data.method]?
       @onHandleError "Unknown method: #{data.method}", data, options
       return
      @responses[data.id] = new Response data, this, options
      @handlers[data.method] data.data, data, @responses[data.id]

     _handleResponse: (data, options) ->
      for f in @wrappers.handleResponse
       return unless f.apply this, arguments
      if not @callsCache[data.id]?
       #Cannot reply
       @errorCallback "Response without call: #{data.id}", data
       return
      try
       if @callsCache[data.id].handle data.data, data
        delete @callsCache[data.id]
      catch e
       @errorCallback e.message, data
       delete @callsCache[data.id]

     _handlePoll: (data, options) ->
      @onHandleError "Poll not implemented", data, options

##WorkerPort class
Used for browser and worker

    class WorkerPort extends Port
     constructor: (worker) ->
      super()
      @worker = worker
      @worker.onmessage = @_onMessage.bind this
      #@worker.onerror = @onCallError.bind this

     _send: (data) ->  @worker.postMessage data
     _respond: (data, options, callback) ->
      @worker.postMessage data
      callback?()

     _onMessage: (e) ->
      data = e.data
      @_handleMessage data

##SocketPort class

    class SocketPort extends Port
     constructor: (socket) ->
      super()
      @socket = socket
      @socket.on 'message', @_onMessage.bind this

     _send: (data) ->  @socket.emit 'message', data
     _respond: (data, options, callback) ->
      @worker.emit 'message', data
      callback?()

     _onMessage: (e) ->
      data = e.data
      @_handleMessage data

##ServerSocketPort class

    class ServerSocketPort extends Port
     constructor: (server) ->
      super()
      @server = server
      @server.on 'connection', @_onConnection.bind this

     _onConnection: (socket) ->
      new SocketPort handlers: @handlers, socket

##AJAX class

    class AjaxHttpPort extends Port
     constructor: (options) ->
      super()
      @protocol = options.protocol
      @host = options.host
      @port = options.port
      @path = options.path ? '/'
      @url = @path
      if @protocol?
       if @host? and not @port?
        @url = "#{@protocol}://#{@host}#{@path}"
       else if @host? and @port?
        @url = "#{@protocol}://#{@host}:#{@port}#{@path}"
      else
       if @host? and not @port?
        @url = "//#{@host}#{@path}"
       else if @host? and @port?
        @url = "//#{@host}:#{@port}#{@path}"

     isStreaming: false

     _onRequest: (xhr) ->
      return unless xhr.readyState is 4
      status = xhr.status
      if ((not status and xhr.responseText? and xhr.responseText != '') or
          (status >= 200 and status < 300) or
          (status is 304))
       try
        jsonData = JSON.parse xhr.responseText
       catch e
        @onCallError 'ParseError', e
        return

       @_handleMessage jsonData, xhr: xhr
      else
       @onCallError 'Cannot connect to server'

     _respond: (data, options, callback) ->
      @errorCallback 'AJAX cannot respond', data
      callback?()

     _send: (data) ->
      data = JSON.stringify data
      xhr = new XMLHttpRequest
      xhr.open 'POST', @url
      xhr.onreadystatechange = =>
       @_onRequest xhr
      xhr.setRequestHeader 'Accept', 'application/json'
      #xhr.setRequestHeader 'Content-Type', 'application/json'
      xhr.send data

     _handleResponse: (data, options) ->
      for f in @wrappers.handleResponse
       return unless f.apply this, arguments
      if not @callsCache[data.id]?
       @errorCallback "Response without call: #{data.id}", data
       return
      call = @callsCache[data.id]
      try
       if call.handle data.data, data
        delete @callsCache[data.id]
       else
        params =
         type: 'poll'
         id: call.id
        params[k] = v for k, v of call.options
        @_send params
      catch e
       @errorCallback e.message, data
       delete @callsCache[data.id]

##NodeHttpPort class

    class NodeHttpPort extends Port
     constructor: (options, http) ->
      super()
      @host = options.host ? 'localhost'
      @port = options.port ? 80
      @path = options.path ? '/'
      @http = http
      @_createHttpOptions()

     isStreaming: false

     _createHttpOptions: ->
      @httpOptions =
       hostname: @host
       port: @port
       path: @path
       method: 'POST'
       agent: false
       headers:
        accept: 'application/json'
       'content-type': 'application/json'

     _onRequest: (res) ->
      data = ''
      #LOG 'STATUS: ' + res.statusCode
      #LOG 'HEADERS: ' + JSON.stringify res.headers
      res.setEncoding 'utf8'
      res.on 'data', (chunk) ->
       data += chunk
      #LOG 'result', res
      res.on 'end', =>
       try
        jsonData = JSON.parse data
       catch e
        @onCallError 'ParseError', e
        return

       @_handleMessage jsonData, response: res

     _respond: (data, options, callback) ->
      data = JSON.stringify data
      res = options.response
      res.setHeader 'content-length', Buffer.byteLength data, 'utf8'
      if callback?
       res.once 'finish', ->
        callback()
       res.once 'close', ->
        callback()

      res.write data
      res.end()

     _send: (data, callbacks) ->
      data = JSON.stringify data
      options = @httpOptions
      options.headers['content-length'] = Buffer.byteLength data, 'utf8'

      req = @http.request options, @_onRequest.bind this
      delete options.headers['content-length']
      req.on 'error', (e) ->
       callbacks.fail? e

      req.write data
      req.end()

     _handleResponse: (data, options) ->
      for f in @wrappers.handleResponse
       return unless f.apply this, arguments
      if not @callsCache[data.id]?
       @errorCallback "Response without call: #{data.id}", data
       return
      call = @callsCache[data.id]
      if not call.handle data.data, data
       params =
        type: 'poll'
        id: call.id
       params[k] = v for k, v of call.options
       @_send params, call.callbacks

##NodeHttpServerPort class

    class NodeHttpServerPort extends Port
     constructor: (options, http) ->
      super()
      @port = options.port
      @http = http

     isStreaming: false

     _onRequest: (req, res) ->
      data = ''
      res.setHeader 'content-type', 'application/json'

      req.on 'data', (chunk) ->
       data += chunk
      req.on 'end', =>
       try
        jsonData = JSON.parse data
       catch e
        @errorCallback 'ParseError', e
        return

       @_handleMessage jsonData, response: res

     _respond: (data, options, callback) ->
      data = JSON.stringify data
      res = options.response
      res.setHeader 'content-length', Buffer.byteLength data, 'utf8'
      if callback?
       res.once 'finish', ->
        callback()
       res.once 'close', ->
        callback()

      res.write data
      res.end()

     listen: ->
      @server = @http.createServer @_onRequest.bind this
      @server.listen @port

     _handlePoll: (data, options) ->
      for f in @wrappers.handleCall
       return unless f.apply this, arguments
      if not @responses[data.id]?
       @onHandleError "Poll without response: #{data.id}", data, options
       return
      @responses[data.id].setOptions options

##NodeHttpsServerPort class

    class NodeHttpsServerPort extends NodeHttpServerPort
     constructor: (options, http) ->
      super options, http
      @_key = options.key
      @_cert = options.cert

     listen: ->
      options =
       key: @_key
       cert: @_cert

      @server = @http.createServer options, @_onRequest.bind this
      @server.listen @port

#IO Module

    IO =
     addPort: (name, port) ->
      IO[name] = port

     ports:
      WorkerPort: WorkerPort
      SocketPort: SocketPort
      AjaxHttpPort: AjaxHttpPort
      NodeHttpPort: NodeHttpPort
      NodeHttpServerPort: NodeHttpServerPort
      NodeHttpsServerPort: NodeHttpsServerPort
      ServerSocketPort: ServerSocketPort

     Helpers:
      progress: (from, to, func) ->
       (progress, data) ->
        func? progress * (to - from) + from, data

     setup_____: (options) ->
      options.workers ?= []
      switch options.platform
       when 'ui'
        for worker in options.workers
         IO.addPort worker.name, new WorkerPort worker.js
        for socket in options.sockets
         IO.addPort socket.name, new SocketPort socket.url
       when 'node'
        for socket in options.listenSockets
         IO.addPort socket.name, new SocketListenPort socket.port
        for socket in options.sockets
         IO.addPort socket.name, new SocketPort socket.url
       when 'worker'
        IO.addPort 'UI', new WorkerListenPort _self

    if exports?
     module.exports = IO
    else
     _self.IO = IO

    _self = this

    if console?.log?
     LOG = console.log.bind console
    else
     LOG = -> null

    if console?.error?
     ERROR_LOG = console.error.bind console
    else
     ERROR_LOG = -> null

    POLL_TYPE =
     progress: true

##Response class

    class Response
     constructor: (data, port, options) ->
      @id = data.id
      @port = port
      @options = options
      @queue = []
      @fresh = true

     progress: (progress, data, callback) ->
      @queue.push
       method: 'progress'
       data: data
       options: {progress: progress}
       callback: callback
      @_handleQueue()

     success: (data) ->
      @queue.push method: 'success', data: data, options: {}
      @_handleQueue()

     fail: (data) ->
      @queue.push method: 'fail', data: data, options: {}
      @_handleQueue()

     setOptions: (options) ->
      @options = options
      @fresh = true
      @_handleQueue()

     _handleQueue: ->
      return unless @queue.length > 0

      d = @queue[0]

      if @port.isStreaming
       @port.respond this, d.method, d.data, d.options, @options, d.callback
       @queue.shift()
      else if @fresh
       @port.respond this, d.method, d.data, d.options, @options, d.callback
       @queue.shift()
       @fresh = false

##Call class

    class Call
     constructor: (@id, @method, @data, @callbacks, @options) -> null

     handle: (data, options) ->
      if not @callbacks[options.status]?
       return if options.status is 'progress'
       #Handled by caller
       throw new Error "No callback registered #{@method} #{options.status}"
      self = this
      setTimeout (-> self.callbacks[options.status] data, options), 0

      if POLL_TYPE[options.status]?
       return false
      else
       return true

##Port base class

    class Port
     constructor: ->
      @handlers = {}
      @callsCache = {}
      @callsCounter = 0
      @id = parseInt Math.random() * 1000
      @responses = {}
      @wrappers =
       send: []
       respond: []
       handleCall: []
       handleResponse: []

     isStreaming: true

     onCallError: (msg, options) ->
      for id, call of @callsCache
       if not call.callbacks.fail?
        ERROR_LOG 'fail callback not registered', call.method, call.data
       else
        call.callbacks.fail error: 'connectionError', msg: msg, options: options, {}

      @callsCache = {}

      @errorCallback msg, options

     onHandleError: (msg, data, options) ->
      @errorCallback msg, data
      response = new Response data, this, options
      response.fail msg

     errorCallback: (msg, options) ->
      ERROR_LOG msg, options

     wrap: (wrapper) ->
      for key, f of wrapper
       if @wrappers[key]?
        @wrappers[key].push f
       else
        this[key] = f

###Send RPC call

     send: (method, data, callbacks, options = {}) ->
      if (typeof callbacks) is 'function'
       callbacks =
        success: callbacks

      for f in @wrappers.send
       return unless f.apply this, [method, data, callbacks, options]

      params = @_createCall method, data, callbacks, options
      @_send params, callbacks

###Respond to a RPC call

     respond: (response, status, data, options = {}, portOptions = {}, callback = null) ->
      for f in @wrappers.respond
       return unless f.apply this, [response, status, data, options, portOptions]

      @_respond (@_createResponse response, status, data, options), portOptions, callback
      if not POLL_TYPE[status]?
       delete @responses[response.id]

###Create Call object
This is a private function

     _createCall: (method, data, callbacks, options) ->
      call = new Call "#{@id}-#{@callsCounter}", method, data, callbacks, options
      @callsCounter++
      @callsCache[call.id] = call

      params =
       type: 'call'
       id: call.id
       method: call.method
       data: call.data

      params[k] = v for k, v of options
      return params

###Create Response object

     _createResponse: (response, status, data, options) ->
      params =
       type: 'response'
       id: response.id
       status: status
       data: data

      params[k] = v for k, v of options

      return params

###Add handler

     on: (method, callback) ->
      @handlers[method] = callback

###Handle incoming message

     _handleMessage: (data, options) ->
      switch data.type
       when 'response'
        @_handleResponse data, options
       when 'call'
        @_handleCall data, options
       when 'poll'
        @_handlePoll data, options

     _handleCall: (data, options) ->
      for f in @wrappers.handleCall
       return unless f.apply this, arguments
      if not @handlers[data.method]?
       @onHandleError "Unknown method: #{data.method}", data, options
       return
      @responses[data.id] = new Response data, this, options
      @handlers[data.method] data.data, data, @responses[data.id]

     _handleResponse: (data, options) ->
      for f in @wrappers.handleResponse
       return unless f.apply this, arguments
      if not @callsCache[data.id]?
       #Cannot reply
       @errorCallback "Response without call: #{data.id}", data
       return
      try
       if @callsCache[data.id].handle data.data, data
        delete @callsCache[data.id]
      catch e
       @errorCallback e.message, data
       delete @callsCache[data.id]

     _handlePoll: (data, options) ->
      @onHandleError "Poll not implemented", data, options

##WorkerPort class
Used for browser and worker

    class WorkerPort extends Port
     constructor: (worker) ->
      super()
      @worker = worker
      @worker.onmessage = @_onMessage.bind this
      #@worker.onerror = @onCallError.bind this

     _send: (data) ->  @worker.postMessage data
     _respond: (data, options, callback) ->
      @worker.postMessage data
      callback?()

     _onMessage: (e) ->
      data = e.data
      @_handleMessage data

##SocketPort class

    class SocketPort extends Port
     constructor: (socket) ->
      super()
      @socket = socket
      @socket.on 'message', @_onMessage.bind this

     _send: (data) ->  @socket.emit 'message', data
     _respond: (data, options, callback) ->
      @worker.emit 'message', data
      callback?()

     _onMessage: (e) ->
      data = e.data
      @_handleMessage data

##ServerSocketPort class

    class ServerSocketPort extends Port
     constructor: (server) ->
      super()
      @server = server
      @server.on 'connection', @_onConnection.bind this

     _onConnection: (socket) ->
      new SocketPort handlers: @handlers, socket

##AJAX class

    class AjaxHttpPort extends Port
     constructor: (options) ->
      super()
      @protocol = options.protocol
      @host = options.host
      @port = options.port
      @path = options.path ? '/'
      @url = @path
      if @protocol?
       if @host? and not @port?
        @url = "#{@protocol}://#{@host}#{@path}"
       else if @host? and @port?
        @url = "#{@protocol}://#{@host}:#{@port}#{@path}"
      else
       if @host? and not @port?
        @url = "//#{@host}#{@path}"
       else if @host? and @port?
        @url = "#{@host}:#{@port}#{@path}"

     isStreaming: false

     _onRequest: (xhr) ->
      return unless xhr.readyState is 4
      status = xhr.status
      if ((not status and xhr.responseText? and xhr.responseText != '') or
          (status >= 200 and status < 300) or
          (status is 304))
       try
        jsonData = JSON.parse xhr.responseText
       catch e
        @onCallError 'ParseError', e
        return

       @_handleMessage jsonData, xhr: xhr
      else
       @onCallError 'Cannot connect to server'

     _respond: (data, options, callback) ->
      @errorCallback 'AJAX cannot respond', data
      callback?()

     _send: (data) ->
      data = JSON.stringify data
      xhr = new XMLHttpRequest
      xhr.open 'POST', @url
      xhr.onreadystatechange = =>
       @_onRequest xhr
      xhr.setRequestHeader 'Accept', 'application/json'
      #xhr.setRequestHeader 'Content-Type', 'application/json'
      xhr.send data

     _handleResponse: (data, options) ->
      for f in @wrappers.handleResponse
       return unless f.apply this, arguments
      if not @callsCache[data.id]?
       @errorCallback "Response without call: #{data.id}", data
       return
      call = @callsCache[data.id]
      try
       if call.handle data.data, data
        delete @callsCache[data.id]
       else
        params =
         type: 'poll'
         id: call.id
        params[k] = v for k, v of call.options
        @_send params
      catch e
       @errorCallback e.message, data
       delete @callsCache[data.id]

##NodeHttpPort class

    class NodeHttpPort extends Port
     constructor: (options, http) ->
      super()
      @host = options.host ? 'localhost'
      @port = options.port ? 80
      @path = options.path ? '/'
      @http = http
      @_createHttpOptions()

     isStreaming: false

     _createHttpOptions: ->
      @httpOptions =
       hostname: @host
       port: @port
       path: @path
       method: 'POST'
       agent: false
       headers:
        accept: 'application/json'
       'content-type': 'application/json'

     _onRequest: (res) ->
      data = ''
      #LOG 'STATUS: ' + res.statusCode
      #LOG 'HEADERS: ' + JSON.stringify res.headers
      res.setEncoding 'utf8'
      res.on 'data', (chunk) ->
       data += chunk
      #LOG 'result', res
      res.on 'end', =>
       try
        jsonData = JSON.parse data
       catch e
        @onCallError 'ParseError', e
        return

       @_handleMessage jsonData, response: res

     _respond: (data, options, callback) ->
      data = JSON.stringify data
      res = options.response
      res.setHeader 'content-length', Buffer.byteLength data, 'utf8'
      if callback?
       res.once 'finish', ->
        callback()
       res.once 'close', ->
        callback()

      res.write data
      res.end()

     _send: (data, callbacks) ->
      data = JSON.stringify data
      options = @httpOptions
      options.headers['content-length'] = Buffer.byteLength data, 'utf8'

      req = @http.request options, @_onRequest.bind this
      delete options.headers['content-length']
      req.on 'error', (e) ->
       callbacks.fail? e

      req.write data
      req.end()

     _handleResponse: (data, options) ->
      for f in @wrappers.handleResponse
       return unless f.apply this, arguments
      if not @callsCache[data.id]?
       @errorCallback "Response without call: #{data.id}", data
       return
      call = @callsCache[data.id]
      if not call.handle data.data, data
       params =
        type: 'poll'
        id: call.id
       params[k] = v for k, v of call.options
       @_send params, call.callbacks

##NodeHttpServerPort class

    class NodeHttpServerPort extends Port
     constructor: (options, http) ->
      super()
      @port = options.port
      @http = http

     isStreaming: false

     _onRequest: (req, res) ->
      data = ''
      res.setHeader 'content-type', 'application/json'

      req.on 'data', (chunk) ->
       data += chunk
      req.on 'end', =>
       try
        jsonData = JSON.parse data
       catch e
        @errorCallback 'ParseError', e
        return

       @_handleMessage jsonData, response: res

     _respond: (data, options, callback) ->
      data = JSON.stringify data
      res = options.response
      res.setHeader 'content-length', Buffer.byteLength data, 'utf8'
      if callback?
       res.once 'finish', ->
        callback()
       res.once 'close', ->
        callback()

      res.write data
      res.end()

     listen: ->
      @server = @http.createServer @_onRequest.bind this
      @server.listen @port

     _handlePoll: (data, options) ->
      for f in @wrappers.handleCall
       return unless f.apply this, arguments
      if not @responses[data.id]?
       @onHandleError "Poll without response: #{data.id}", data, options
       return
      @responses[data.id].setOptions options

##NodeHttpsServerPort class

    class NodeHttpsServerPort extends NodeHttpServerPort
     constructor: (options, http) ->
      super options, http
      @_key = options.key
      @_cert = options.cert

     listen: ->
      options =
       key: @_key
       cert: @_cert

      @server = @http.createServer options, @_onRequest.bind this
      @server.listen @port

#IO Module

    IO =
     addPort: (name, port) ->
      IO[name] = port

     ports:
      WorkerPort: WorkerPort
      SocketPort: SocketPort
      AjaxHttpPort: AjaxHttpPort
      NodeHttpPort: NodeHttpPort
      NodeHttpServerPort: NodeHttpServerPort
      NodeHttpsServerPort: NodeHttpsServerPort
      ServerSocketPort: ServerSocketPort

     Helpers:
      progress: (from, to, func) ->
       (progress, data) ->
        func? progress * (to - from) + from, data

     setup_____: (options) ->
      options.workers ?= []
      switch options.platform
       when 'ui'
        for worker in options.workers
         IO.addPort worker.name, new WorkerPort worker.js
        for socket in options.sockets
         IO.addPort socket.name, new SocketPort socket.url
       when 'node'
        for socket in options.listenSockets
         IO.addPort socket.name, new SocketListenPort socket.port
        for socket in options.sockets
         IO.addPort socket.name, new SocketPort socket.url
       when 'worker'
        IO.addPort 'UI', new WorkerListenPort _self

    if exports?
     module.exports = IO
    else
     _self.IO = IO


throw errors

throw errors

    _self = this

##Response class

    class Response
     constructor: (data, port, options) ->
      @id = data.id
      @port = port
      @options = options

     progress: (progress, data) ->
      @port.respond this, 'progress', data, progress: progress, @options

     success: (data) ->
      @port.respond this, 'success', data, {}, @options

     fail: (data) ->
      @port.respond this, 'fail', data, {}, @options

##Call class

    class Call
     constructor: (@id, @method, @data, @callbacks) -> null

     handle: (data, options) ->
      if not @callbacks[options.status]?
       throw new Error "No callback registered #{@method} #{options.status}"
      @callbacks[options.status] data, options

##Port base class

    class Port
     constructor: ->
      @handlers = {}
      @callsCache = {}
      @callsCounter = 0
      @wrappers =
       send: []
       respond: []
       handleCall: []
       handleResponse: []

     onerror: (msg, options) ->
      console.log msg, options

     wrap: (wrapper) ->
      for key, f of wrapper
       if @wrappers[key]?
        @wrappers[key].push f
       else
        this[key] = f

###Send RPC call

     send: (method, data, callbacks, options = {}) ->
      if (typeof callbacks) is 'function'
       callbacks =
        success: callbacks

      for f in @wrappers.send
       return unless f.apply this, [method, data, callbacks, options]

      @_send @_createCall method, data, callbacks, options

###Respond to a RPC call

     respond: (response, status, data, options = {}, portOptions = {}) ->
      for f in @wrappers.respond
       return unless f.apply this, [response, status, data, options, portOptions]

      @_respond (@_createResponse response, status, data, options), portOptions

###Create Call object
This is a private function

     _createCall: (method, data, callbacks, options) ->
      call = new Call @callsCounter, method, data, callbacks
      @callsCounter++
      @callsCache[call.id] = call

      params =
       type: 'call'
       id: call.id
       method: call.method
       data: call.data

      params[k] = v for k, v of options
      return params

###Create Response object

     _createResponse: (response, status, data, options) ->
      params =
       type: 'response'
       id: response.id
       status: status
       data: data

      params[k] = v for k, v of options

      return params

###Add handler

     on: (method, callback) ->
      @handlers[method] = callback

###Handle incoming message

     _handleMessage: (data, options) ->
      switch data.type
       when 'response'
        @_handleResponse data, options
       when 'call'
        @_handleCall data, options

     _handleCall: (data, options) ->
      for f in @wrappers.handleCall
       return unless f.apply this, arguments
      if not @handlers[data.method]?
       throw new Error "Unknown method: #{data.method}"
      @handlers[data.method] data.data, data, new Response data, this, options

     _handleResponse: (data, options) ->
      for f in @wrappers.handleResponse
       return unless f.apply this, arguments
      if not @callsCache[data.id]?
       throw new Error "Response without call: #{data.id}"
      @callsCache[data.id].handle data.data, data

##WorkerPort class
Used for browser and worker

    class WorkerPort extends Port
     constructor: (worker) ->
      super()
      @worker = worker
      @worker.onmessage = @_onMessage.bind this
      @worker.onerror = @_onError.bind this

     _send: (data) ->  @worker.postMessage data
     _respond: (data) -> @worker.postMessage data

     _onMessage: (e) ->
      data = e.data
      @_handleMessage data

     _onError: (e) -> console.log e

##SocketPort class

    class SocketPort extends Port
     constructor: (socket) ->
      super()
      @socket = socket
      @socket.on 'message', @_onMessage.bind this

     _send: (data) ->  @socket.emit 'message', data
     _respond: (data) -> @worker.emit 'message', data

     _onMessage: (e) ->
      data = e.data
      @_handleMessage data

##ServerSocketPort class

    class ServerSocketPort extends Port
     constructor: (server) ->
      super()
      @server = server
      @server.on 'connection', @_onConnection.bind this

     _onConnection: (socket) ->
      new SocketPort handlers: @handlers, socket

##NodeHttpPort class

    class NodeHttpPort extends Port
     constructor: (options, http) ->
      super()
      @host = options.host ? 'localhost'
      @port = options.port ? 80
      @path = options.path ? '/'
      @http = http
      @_createHttpOptions()

     _createHttpOptions: ->
      @httpOptions =
       hostname: @host
       port: @port
       path: @path
       method: 'POST'
       headers:
        accept: 'application/json'
       'content-type': 'application/json'

     _onRequest: (res) ->
      data = ''
      #console.log 'STATUS: ' + res.statusCode
      #console.log 'HEADERS: ' + JSON.stringify res.headers
      res.setEncoding 'utf8'
      res.on 'data', (chunk) ->
       data += chunk
      #console.log 'result', res
      res.on 'end', =>
       try
        jsonData = JSON.parse data
       catch e
        console.log 'ParseError', e
        return

       @_handleMessage jsonData, response: res

     _respond: (data, options) ->
      data = JSON.stringify data
      res = options.response
      res.setHeader 'content-length', data.length
      res.write data
      res.end()

     _send: (data) ->
      data = JSON.stringify data
      options = @httpOptions
      options.headers['content-length'] = data.length

      req = @http.request options, @_onRequest.bind this
      delete options.headers['content-length']
      req.on 'error', (e) ->
       console.log 'error', e

      req.write data
      req.end()

##NodeHttpServerPort class

    class NodeHttpServerPort extends Port
     constructor: (options, http) ->
      super()
      @port = options.port
      @http = http

     _onRequest: (req, res) ->
      data = ''
      res.setHeader 'content-type', 'application/json'

      req.on 'data', (chunk) ->
       data += chunk
      req.on 'end', =>
       try
        jsonData = JSON.parse data
       catch e
        console.log 'ParseError', e
        return

       @_handleMessage jsonData, response: res

     _respond: (data, options) ->
      data = JSON.stringify data
      res = options.response
      res.setHeader 'content-length', data.length
      res.write data
      res.end()

     listen: ->
      @server = @http.createServer @_onRequest.bind this
      @server.listen @port

#IO Module

    IO =
     addPort: (name, port) ->
      IO[name] = port

     ports:
      WorkerPort: WorkerPort
      SocketPort: SocketPort
      NodeHttpPort: NodeHttpPort
      NodeHttpServerPort: NodeHttpServerPort
      ServerSocketPort: ServerSocketPort

     setup: (options) ->
      options.workers ?= []
      switch options.platform
       when 'ui'
        for worker in options.workers
         IO.addPort worker.name, new WorkerPort worker.js
        for socket in options.sockets
         IO.addPort socket.name, new SocketPort socket.url
       when 'node'
        for socket in options.listenSockets
         IO.addPort socket.name, new SocketListenPort socket.port
        for socket in options.sockets
         IO.addPort socket.name, new SocketPort socket.url
       when 'worker'
        IO.addPort 'UI', new WorkerListenPort _self

    if exports?
     module.exports = IO
    else
     _self.IO = IO

    _self = this

##Response class

    class Response
     constructor: (data, port, options) ->
      @id = data.id
      @port = port
      @options = options

     progress: (progress, data) ->
      @port.respond this, 'progress', data, progress: progress, @options

     success: (data) ->
      @port.respond this, 'success', data, {}, @options

     fail: (data) ->
      @port.respond this, 'fail', data, {}, @options

##Call class

    class Call
     constructor: (@id, @method, @data, @callbacks) -> null

     handle: (data, options) ->
      if not @callbacks[options.status]?
       throw new Error "No callback registered #{@method} #{options.status}"
      @callbacks[options.status] data, options

##Port base class

    class Port
     constructor: ->
      @handlers = {}
      @callsCache = {}
      @callsCounter = 0
      @wrappers =
       send: []
       respond: []
       handleCall: []
       handleResponse: []

     onerror: (msg, options) ->
      console.log msg, options

     wrap: (wrapper) ->
      for key, f of wrapper
       if @wrappers[key]?
        @wrappers[key].push f
       else
        this[key] = f

###Send RPC call

     send: (method, data, callbacks, options = {}) ->
      if (typeof callbacks) is 'function'
       callbacks =
        success: callbacks

      for f in @wrappers.send
       return unless f.apply this, [method, data, callbacks, options]

      @_send @_createCall method, data, callbacks, options

###Respond to a RPC call

     respond: (response, status, data, options = {}, portOptions = {}) ->
      for f in @wrappers.respond
       return unless f.apply this, [response, status, data, options, portOptions]

      @_respond (@_createResponse response, status, data, options), portOptions

###Create Call object
This is a private function

     _createCall: (method, data, callbacks, options) ->
      call = new Call @callsCounter, method, data, callbacks
      @callsCounter++
      @callsCache[call.id] = call

      params =
       type: 'call'
       id: call.id
       method: call.method
       data: call.data

      params[k] = v for k, v of options
      return params

###Create Response object

     _createResponse: (response, status, data, options) ->
      params =
       type: 'response'
       id: response.id
       status: status
       data: data

      params[k] = v for k, v of options

      return params

###Add handler

     on: (method, callback) ->
      @handlers[method] = callback

###Handle incoming message

     _handleMessage: (data, options) ->
      switch data.type
       when 'response'
        @_handleResponse data, options
       when 'call'
        @_handleCall data, options

     _handleCall: (data, options) ->
      for f in @wrappers.handleCall
       return unless f.apply this, arguments
      return unless @handlers[data.method]?
      @handlers[data.method] data.data, data, new Response data, this, options

     _handleResponse: (data, options) ->
      for f in @wrappers.handleResponse
       return unless f.apply this, arguments
      return unless @callsCache[data.id]?
      @callsCache[data.id].handle data.data, data

##WorkerPort class
Used for browser and worker

    class WorkerPort extends Port
     constructor: (worker) ->
      super()
      @worker = worker
      @worker.onmessage = @_onMessage.bind this
      @worker.onerror = @_onError.bind this

     _send: (data) ->  @worker.postMessage data
     _respond: (data) -> @worker.postMessage data

     _onMessage: (e) ->
      data = e.data
      @_handleMessage data

     _onError: (e) -> console.log e

##SocketPort class

    class SocketPort extends Port
     constructor: (socket) ->
      super()
      @socket = socket
      @socket.on 'message', @_onMessage.bind this

     _send: (data) ->  @socket.emit 'message', data
     _respond: (data) -> @worker.emit 'message', data

     _onMessage: (e) ->
      data = e.data
      @_handleMessage data

##ServerSocketPort class

    class ServerSocketPort extends Port
     constructor: (server) ->
      super()
      @server = server
      @server.on 'connection', @_onConnection.bind this

     _onConnection: (socket) ->
      new SocketPort handlers: @handlers, socket

##NodeHttpPort class

    class NodeHttpPort extends Port
     constructor: (options, http) ->
      super()
      @host = options.host ? 'localhost'
      @port = options.port ? 80
      @path = options.path ? '/'
      @http = http
      @_createHttpOptions()

     _createHttpOptions: ->
      @httpOptions =
       hostname: @host
       port: @port
       path: @path
       method: 'POST'
       headers:
        accept: 'application/json'
       'content-type': 'application/json'

     _onRequest: (res) ->
      data = ''
      #console.log 'STATUS: ' + res.statusCode
      #console.log 'HEADERS: ' + JSON.stringify res.headers
      res.setEncoding 'utf8'
      res.on 'data', (chunk) ->
       data += chunk
      #console.log 'result', res
      res.on 'end', =>
       try
        jsonData = JSON.parse data
       catch e
        console.log 'ParseError', e
        return

       @_handleMessage jsonData, response: res

     _respond: (data, options) ->
      data = JSON.stringify data
      res = options.response
      res.setHeader 'content-length', data.length
      res.write data
      res.end()

     _send: (data) ->
      data = JSON.stringify data
      options = @httpOptions
      options.headers['content-length'] = data.length

      req = @http.request options, @_onRequest.bind this
      delete options.headers['content-length']
      req.on 'error', (e) ->
       console.log 'error', e

      req.write data
      req.end()

##NodeHttpServerPort class

    class NodeHttpServerPort extends Port
     constructor: (options, http) ->
      super()
      @port = options.port
      @http = http

     _onRequest: (req, res) ->
      data = ''
      res.setHeader 'content-type', 'application/json'

      req.on 'data', (chunk) ->
       data += chunk
      req.on 'end', =>
       try
        jsonData = JSON.parse data
       catch e
        console.log 'ParseError', e
        return

       @_handleMessage jsonData, response: res

     _respond: (data, options) ->
      data = JSON.stringify data
      res = options.response
      res.setHeader 'content-length', data.length
      res.write data
      res.end()

     listen: ->
      @server = @http.createServer @_onRequest.bind this
      @server.listen @port

#IO Module

    IO =
     addPort: (name, port) ->
      IO[name] = port

     ports:
      WorkerPort: WorkerPort
      SocketPort: SocketPort
      NodeHttpPort: NodeHttpPort
      NodeHttpServerPort: NodeHttpServerPort
      ServerSocketPort: ServerSocketPort

     setup: (options) ->
      options.workers ?= []
      switch options.platform
       when 'ui'
        for worker in options.workers
         IO.addPort worker.name, new WorkerPort worker.js
        for socket in options.sockets
         IO.addPort socket.name, new SocketPort socket.url
       when 'node'
        for socket in options.listenSockets
         IO.addPort socket.name, new SocketListenPort socket.port
        for socket in options.sockets
         IO.addPort socket.name, new SocketPort socket.url
       when 'worker'
        IO.addPort 'UI', new WorkerListenPort _self

    if exports?
     module.exports = IO
    else
     _self.IO = IO


New prefixes for method signatures

New prefixes for method signatures

# Batman.Observable

`Batman.Observable` is a mixin which gives objects the ability to notify subscribers to changes on its properties. `Observable` also adds functionality for observing _keypaths_: arbitrarily deeply nested properties on objects. All `Batman.Object`s, their subclasses and instances are observable by default.

## ::.isObservable[= true] : boolean

`isObservable` will return `true` when the current object is able to be observed, or `false` if it is not.

## ::get(keypath: string) : value

Retrieves the value at a `key` on an object. Accepts keypaths.

_Note_: `get` must be used for property access on any object in `Batman`'s world. This is so that Batman can implement neat things like automatic dependency calculation for computed properties, property caching where it is safe, and smart storage mechanisms. With Batman, you must use `get` instead of the regular `.` for property access.

    test "get retrieves properties on Batman objects", ->
      song = new Batman.Object({length: 340, bpm: 120})
      equal song.get("length"), 340
      equal song.get("bpm"), 120

    test "get retrieves properties on nested Batman objects using keypaths", ->
      post = new Batman.Object
        text: "Hello World!"
        author: new Batman.Object
          name: "Harry"
      equal post.get("author.name"), "Harry"

    test "get retrieves properties on Batman objects when . property access doesn't", ->
      song = new Batman.Model({length: 340, bpm: 120})
      equal typeof song.length, "undefined"
      equal song.get("length"), 340

## ::set(keypath: string, newValue) : newValue

Stores the `value` at a `key` on an object. Accepts keypaths. Returns the new value of the property.

_Note_: Once more, `set` must be used for property mutation on all objects in the `Batman` world. This is again so that Batman can implement useful functionality like cache busting, eager recalculation of computed properties, and smarter storage.

_Note_: Custom setters can mutate the value during setting, so the value which was passed to `set` and `set`'s return value are not guaranteed to be identical.

    test "set stores properties on batman objects.", ->
      song = new Batman.Object({length: 340, bpm: 120})
      equal song.get("length"), 340
      equal song.set("length", 1000), 1000
      equal song.get("length"), 1000

    test "set stores properties on nested Batman objects using keypaths", ->
      author = new Batman.Object
        name: "Harry"
      post = new Batman.Object
        text: "Hello World!"
        author: author
      equal post.set("author.name", "Nick"), "Nick"
      equal author.get("name"), "Nick", "The value was set on the nested object."

    test "set is incompatible with '.' property mutation", ->
      song = new Batman.Model({length: 340, bpm: 120})
      equal song.get("length"), 340
      equal song.length = 1000, 1000
      equal song.get("length"), 340, "The song length reported by Batman is unchanged because set wasn't used to change the value."

## ::unset(keypath: string) : value

Removes the value at the given `keypath`, leaving it `undefined`. Accepts keypaths. Returns the value the property had before unsetting.

`unset` is roughly equivalent to `set(keypath, undefined)`, however, custom properties can define a nonstandard `unset` function, so it is best to use `unset` instead of `set(keypath, undefined)` wherever possible.

    test "unset removes the property on Batman objects", ->
      song = new Batman.Object({length: 340, bpm: 120})
      equal song.get("length"), 340
      equal song.unset("length"), 340
      equal song.get("length"), undefined, "The value is unset."

    test "unset removes the property at a keypath", ->
      author = new Batman.Object
        name: "Harry"
      post = new Batman.Object
        text: "Hello World!"
        author: author
      equal post.unset("author.name"), "Harry"
      equal author.get("name"), undefined, "The value was unset on the nested object."

## ::getOrSet(keypath: string, valueFunction: Function) : value

Assigns the `keypath` to the result of calling `valueFunction` if `keypath` is currently falsey. Returns the value of the property after the operation, whether it has changed or not. Equivalent to CoffeeScript's `||=` operator.

    test "getOrSet doesn't set the property if it exists", ->
      song = new Batman.Object({length: 340, bpm: 120})
      equal song.getOrSet("length", -> 500), 340
      equal song.get("length"), 340

    test "getOrSet sets the property if it is falsey", ->
      song = new Batman.Object({length: 340, bpm: 120})
      equal song.getOrSet("artist", -> "Elvis"), "Elvis"
      equal song.get("artist"), "Elvis"

## ::observe(key: string, observerCallback: Function) : this

Adds a handler to call when the value of the property at the `key` changes upon `set`ting. Accepts keypaths.

`observe` is the very core of Batman's usefulness. As long as `set` is used everywhere to do property mutation, any object can be observed for changes to its properties. This is critical to the concept of bindings, which Batman uses for its views.

The `observerCallback` gets called with the arguments `newValue, oldValue`, whenever the `key` changes.

Returns the object `observe` was called upon.

    test "observe attaches handlers which get called upon change", ->
      result = null
      song = new Batman.Object({length: 340, bpm: 120})
      song.observe "length", (newValue, oldValue) -> result = [newValue, oldValue]
      equal song.set("length", 200), 200
      deepEqual result, [200, 340]
      equal song.set("length", 300), 300
      deepEqual result, [300, 200]

_Note_: `observe` works excellently on keypaths. If you attach a handler to a "deep" keypath, it will fire when any segment of the keypath changes, passing in the new value at the end of the keypath.

    test "observe attaches handlers which get called upon change", ->
      result = null
      author = new Batman.Object
        name: "Harry"
      post = new Batman.Object
        text: "Hello World!"
        author: author
      post.observe "author.name", (newName, oldName) ->
        result = [newName, oldName]
      newAuthor = new Batman.Object({name: "James"})
      post.set "author", newAuthor
      deepEqual result, ["James", "Harry"], "The observer fired when the 'author' segment of the keypath changed."

## ::observeAndFire(key: string, observerCallback: Function) : this

Adds the `observerCallback` as an observer to `key`, and fires it immediately. Accepts the exact same arguments and follows the same semantics as `Observable::observe`, but the observer is fired with the current value of the keypath it observes synchronously during the call to `observeAndFire`.

_Note_: During the initial synchronous firing of the `callback`, the `newValue` and `oldValue` arguments will be the same value: the current value of the property. This is because the old value of the property is not cached and therefore unavailable. If your observer needs the old value of the property, you must attach it before the `set` on the property happens.

    test "observeAndFire calls the observer upon attaching it with the currentValue of the property", ->
      result = null
      song = new Batman.Object({length: 340, bpm: 120})
      song.observeAndFire "length", (newValue, oldValue) -> result = [newValue, oldValue]
      deepEqual result, [340, 340]
      equal song.set("length", 300), 300
      deepEqual result, [300, 340]

## ::observeOnce(key: string, observerCallback: Function)

Behaves the same way as `Observable::observe`, except that once `observerCallback` has been executed for the first time, it will remove itself as an observer to `key`.

    test "observeOnce only calls observerCallback when key is modified for the first time", ->
      result = null
      song = new Batman.Object({length: 340, bpm: 120})
      song.observeOnce "length", (newValue, oldValue) -> result = [newValue, oldValue]
      equal song.set("length", 200), 200
      deepEqual result, [200, 340]
      equal song.set("length", 300), 300
      deepEqual result, [200, 340], "The observer was not fired for the second update"

## ::forget([key: string[, observerCallback: Function]]) : this

If `observerCallback` and `key` are given, that observer is removed from the observers on `key`. If only a `key` is given, all observers on that key are removed. If no `key` is given, all observers on all keys are removed. Accepts keypaths.

Returns the object on which `forget` was called.

    test "forget removes an observer from a key if the key and the observer are given", ->
      result = null
      song = new Batman.Object({length: 340, bpm: 120})
      observer = (newValue, oldValue) -> result = [newValue, oldValue]
      song.observe "length", observer
      equal song.set("length", 200), 200
      deepEqual result, [200, 340]
      song.forget "length", observer
      equal song.set("length", 300), 300
      deepEqual result, [200, 340], "The logged values haven't changed because the observer hasn't fired again."

    test "forget removes all observers from a key if only the key is given", ->
      results = []
      song = new Batman.Object({length: 340, bpm: 120})
      observerA = ((newValue, oldValue) -> results.push [newValue, oldValue])
      observerB = ((newValue, oldValue) -> results.push [newValue, oldValue])
      song.observe "length", observerA
      song.observe "length", observerB
      equal song.set("length", 200), 200
      equal results.length, 2, "Both length observers fired."
      song.forget("length")
      equal song.set("length", 300), 300
      equal results.length, 2, "Nothing more has been added because neither observer fired."

    test "forget removes all observers from all keys if no key is given", ->
      results = []
      song = new Batman.Object({length: 340, bpm: 120})
      observerA = ((newValue, oldValue) -> results.push [newValue, oldValue])
      observerB = ((newValue, oldValue) -> results.push [newValue, oldValue])
      song.observe "length", observerA
      song.observe "bpm", observerB
      equal song.set("length", 200), 200
      equal results.length, 1, "The length observer fired."
      song.forget()
      equal song.set("length", 300), 300
      equal song.set("bpm", 130), 130
      equal results.length, 1, "Nothing more has been logged because neither observer fired."

# Batman.Observable

`Batman.Observable` is a mixin which gives objects the ability to notify subscribers to changes on its properties. `Observable` also adds functionality for observing _keypaths_: arbitrarily deeply nested properties on objects.

## get(keypath) : value

Retrieves the value at a `key` on an object. Accepts keypaths.

_Note_: `get` must be used for property access on any object in `Batman`'s world. This is so that Batman can implement neat things like automatic dependency calculation for computed properties, property caching where it is safe, and smart storage mechanisms. With Batman, you must use `get` instead of normal `.` property access.

    test 'get retrieves properties on Batman objects', ->
      song = Batman({length: 340, bpm: 120})
      equal song.get('length'), 340
      equal song.get('bpm'), 120

    test 'get retrieves properties on nested Batman objects using keypaths', ->
      post = Batman
        text: "Hello World!"
        author: Batman
          name: "Harry"
      equal post.get('author.name'), "Harry"

    test "get retrieves properties on Batman objects when . property access doesn't", ->
      song = new Batman.Model({length: 340, bpm: 120})
      equal typeof song.length, "undefined"
      equal song.get('length'), 340

## set(keypath, newValue) : newValue

Stores the `value` at a `key` on an object. Accepts keypaths. Returns the new value of the property.

_Note_: Once more, `set` must be used for property mutation on all objects in the `Batman` world. This is again so that Batman can implement useful functionality like cache busting, eager recalculation of computed properties, and smarter storage.

_Note_: Custom setters can mutate the value during setting, so the value which was passed to `set` and `set`'s return value are not guaranteed to be identical.

    test 'set stores properties on batman objects.', ->
      song = Batman({length: 340, bpm: 120})
      equal song.get('length'), 340
      equal song.set('length', 1000), 1000
      equal song.get('length'), 1000

    test 'set stores properties on nested Batman objects using keypaths', ->
      author = Batman
        name: "Harry"
      post = Batman
        text: "Hello World!"
        author: author
      equal post.set('author.name', "Nick"), "Nick"
      equal author.get('name'), "Nick", "The value was set on the nested object."

    test "set is incompatible with '.' property mutation", ->
      song = new Batman.Model({length: 340, bpm: 120})
      equal song.get('length'), 340
      equal song.length = 1000, 1000
      equal song.get('length'), 340, "The song length reported by Batman is unchanged because set wasn't used to change the value."

## unset(keypath) : value

Removes the value at the given `keypath`, leaving it `undefined`. Accepts keypaths. Returns the value the property had before unsetting.

`unset` is roughly equivalent to `set(keypath, undefined)`, however, custom properties can define a nonstandard `unset` function, so it is best to use `unset` instead of `set(keypath, undefined)` wherever possible.

    test "unset removes the property on Batman objects", ->
      song = Batman({length: 340, bpm: 120})
      equal song.get('length'), 340
      equal song.unset('length'), 340
      equal song.get('length'), undefined, "The value is unset."

    test "unset removes the property at a keypath", ->
      author = Batman
        name: "Harry"
      post = Batman
        text: "Hello World!"
        author: author
      equal post.unset('author.name'), "Harry"
      equal author.get('name'), undefined, "The value was unset on the nested object."

## observe(key, observerCallback) : this

Adds a handler to call when the value of the property at the `key` changes upon `set`ting. Accepts keypaths.

`observe` is the very core of Batman's usefulness. As long as `set` is used everywhere to do property mutation, any object can be observed for changes to its properties. This is critical to the concept of bindings, which Batman uses for its views.

The `observerCallback` gets called whenever the `key` changes with the arguments `newValue, oldValue`.

Returns the object `observe` was called upon.

    test "observe attaches handlers which get called upon change", ->
      result = null
      song = Batman({length: 340, bpm: 120})
      song.observe 'length', (newValue, oldValue) -> result = [newValue, oldValue]
      equal song.set('length', 200), 200
      deepEqual result, [200, 340]
      equal song.set('length', 300), 300
      deepEqual result, [300, 200]

_Note_: `observe` works excellently on keypaths. If you attach a handler to a "deep" keypath, it will fire any time the value of that keypath changes, which is another way of saying the handler will fire when any segment of the keypath changes, passing in the new value at the end of the keypath.

    test "observe attaches handlers which get called upon change", ->
      result = null
      author = Batman
        name: "Harry"
      post = Batman
        text: "Hello World!"
        author: author
      post.observe('author.name', (newName, oldName) -> result = [newName, oldName])
      post.set 'author', newAuthor = Batman({name: "James"})
      deepEqual result, ["James", "Harry"], "The observer fired when the 'author' segment of the keypath changed."

## observeAndFire(key, observerCallback) : this

Adds the `observerCallback` as an observer to `key`, and fires it immediately. Accepts the exact same arguments and follows the same semantics as `Observable::observe`, but the observer is fired with the current value of the keypath it observes synchronously during the call to `observeAndFire`.

During the initial synchronous firing of the `callback`, the `newValue` and `oldValue` arguments will be the same value: the current value of the property. This is because the old value of the property is not cached and therefore unavailable. If your observer needs the old value of the property, you must attach it before the `set` on the property happens.

    test "observeAndFire calls the observer upon attaching it with the currentValue of the property", ->
      result = null
      song = Batman({length: 340, bpm: 120})
      song.observeAndFire 'length', (newValue, oldValue) -> result = [newValue, oldValue]
      deepEqual result, [340, 340]
      equal song.set('length', 300), 300
      deepEqual result, [300, 340]

## forget([key [, observerCallback]]) : this

If `observerCallback` and `key` are given, that observer is removed from the observers on `key`. If only a `key` is given, all observers on that key are removed. If no `key` is given, all observers on all keys are removed. Accepts keypaths.

Returns the object on which `forget` was called.

    test "forget removes an observer from a key if the key and the observer are given", ->
      result = null
      song = Batman({length: 340, bpm: 120})
      observer = (newValue, oldValue) -> result = [newValue, oldValue]
      song.observe 'length', observer
      equal song.set('length', 200), 200
      deepEqual result, [200, 340]
      song.forget 'length', observer
      equal song.set('length', 300), 300
      deepEqual result, [200, 340], "The logged values haven't changed because the observer hasn't fired again."

    test "forget removes all observers from a key if only the key is given", ->
      results = []
      song = Batman({length: 340, bpm: 120})
      observerA = ((newValue, oldValue) -> results.push [newValue, oldValue])
      observerB = ((newValue, oldValue) -> results.push [newValue, oldValue])
      song.observe 'length', observerA
      song.observe 'length', observerB
      equal song.set('length', 200), 200
      equal results.length, 2, "Both length observers fired."
      song.forget('length')
      equal song.set('length', 300), 300
      equal results.length, 2, "Nothing more has been added because neither observer fired."

    test "forget removes all observers from all keys if no key is given", ->
      results = []
      song = Batman({length: 340, bpm: 120})
      observerA = ((newValue, oldValue) -> results.push [newValue, oldValue])
      observerB = ((newValue, oldValue) -> results.push [newValue, oldValue])
      song.observe 'length', observerA
      song.observe 'bpm', observerB
      equal song.set('length', 200), 200
      equal results.length, 1, "The length observer fired."
      song.forget()
      equal song.set('length', 300), 300
      equal song.set('bpm', 130), 130
      equal results.length, 1, "Nothing more has been logged because neither observer fired."

## getOrSet(keypath, valueFunction) : value

Assigns the `keypath` to the result of calling the `valueFunction` if the current value at the `keypath` is falsey. Returns the value of the property after the operation, be it changed or not. Equivalent to CoffeeScript's `||=` operator.

    test "getOrSet doesn't set the property if it exists", ->
      song = Batman({length: 340, bpm: 120})
      equal song.getOrSet('length', -> 500), 340
      equal song.get('length'), 340

    test "getOrSet sets the property if it is falsey", ->
      song = Batman({length: 340, bpm: 120})
      equal song.getOrSet('artist', -> "Elvis"), "Elvis"
      equal song.get('artist'), "Elvis"


fixed formatting

fixed formatting

# CLASS: Base

All classes extend this.

    module.exports = class Base

## CONSTRUCTOR

**new Base()**

Creates [Base][Base] instance. Call `super` from descendant class
if **___runtime** is required.

      constructor: -> Object.defineProperty this, '___runtime',
        enumerable:no, writable:no, configurable:no, value:{}

## PROPERTIES

### #___runtime
* Type: [Object][Object]

Private property which serves as a heap of data that should not
be exposed on the instance. Created with enumerable, configurable
and writable set **no**.

[Base]: ./base.litcoffee
[Object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object

# CLASS: Base

All classes extend this.

    module.exports = class Base

## CONSTRUCTOR

**new Base()**

Creates **Base** instance. Call `super` from descendant class
if **___runtime** is required.

      constructor: -> Object.defineProperty this, '___runtime',
        enumerable:no, writable:no, configurable:no, value:{}

## PROPERTIES

**___runtime**
* Type: [Object][Object]

Private property which serves as a heap of data that should not
be exposed on the instance. Created with enumerable, configurable
and writable set **no**.

[Object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object


Updated README links

Updated README links

#  THE JELLI GAME ENGINE  #
Programmed by Margaret Russel

- - -

##  Introduction  ##

This folder contains all of the source code for the Jelli Game Engine.
Jelli is written in Literate CoffeeScript, which means that each source file can be read as Markdown.
The code blocks (indented with four spaces) in each file are the CoffeeScript code.
This file is the [`README`](README.litcoffee), and is, in fact, a file in the engine's source.

####  Browser compatibility  ####

The anticipated (ie, untested) browser compatibility for the Jelli Game Engine and its various modules is as follows:

| Chrome | Firefox | Internet Explorer | Opera | Safari |
| :----: | :-----: | :---------------: | :---: | :----: |
|    7   |   4.0   |         9         |   12  |   5.1  |

A few specific features have higher requirements, however:

#####  touch events  #####

Touch events are often either not supported or hidden behind a preference on desktop browsers.
In addition, touch events on IE mobile is only supported after version 11 with Windows Phone 8.1.

#####  mouse events  #####

Mouse events likewise have higher requirements, due to the engine's dependence on `MouseEvent.pageX` and `MouseEvent.pageY`.
This is supported in all major browsers, but may not work in more antiquated ones (for example, Chrome requires at least version 45).

#####  pixelated images  #####

The Jelli Game Engine currently handles canvas upscaling using CSS to create a pixelated appearance.
This feature is only supported in recent browsers, so older ones may display a blurry image on larger screens.

##### additional notes  #####

Not all browsers will act the same way when multiple elements share the same `id` or `name`.
Non–Gecko-based browsers do not conform with the spec for `HTMLCollection.namedItem()` in these instances and will likely break the script.
Of course, giving multiple elements the same `id` is bad practice anyway, so this is unlikely to pose an issue.

Safari (including on iOS) can sometimes fail to properly clear the canvas in select instances, for reasons that escape me and are likely a bug in Safari code.
(In one instance, one canvas would only clear if a *different* canvas was set to clear on area change, regardless of whether area change actually ever occurred.
I really have no solution to this except mess around until you can get things to work.)

###  Modules:  ###

The Jelli Game Engine depends upon, and is developed alongside, several modules, each seperately encapsulated for portability and reusability.
The modules at this time are:

- [`Screen`](modules/Screen.litcoffee)
- [`Control`](modules/Control.litcoffee)
- [`Sheet`](modules/Sheet.litcoffee)
- [`Letters`](modules/Letters.litcoffee)
- [`Tileset`](modules/Tileset.litcoffee)

>   [Issue #51](https://github.com/literallybenjam/jelli/issues/51) :
    Support for a `Filter` module is also planned.

You can view the source for each module by viewing the appropriately named `.litcoffee` file in the [modules](modules) directory.

###  Engine:  ###

The game engine, which depends on the aformentioned modules, is itself modular, comprised of a number of interdependent components.
At this time, the list of these components is as follows:

1. [`Jelli`](engine/01 Jelli.litcoffee)
2. [`Game`](engine/02 Game.litcoffee)
3. [`Area`](engine/03 Area.litcoffee)
4. [`Collection`](engine/04 Collection.litcoffee)
5. [`Unit`](engine/05 Unit.litcoffee)
6. [`PlacementImage`](engine/06 PlacementImage.litcoffee)
7. [`Character`](engine/07 Character.litcoffee)
8. [`Text`](engine/08 Text.litcoffee)

Documentation for each engine module is available in the [engine](engine) directory.

###  How to read this engine:  ###

The best starting point for most readers and developers is reading through the documentation files for the engine itself, starting with the [`Introduction`](engine/00 Introduction.litcoffee), as these provide all of the interfaces necessary for game development.
Nevertheless, the engine relies on the other modules for many of its tasks, and will reference them from time to time.
A policy of focusing on the engine and looking up the other modules when needed is probably the best approach to becoming familiar with the system as a whole.

It is not necessary to understand the code behind this engine in order to put it into use.
In fact, the extensive documentation provided for the engine exists precisely to make it accessible without forcing users to dig through code.
When browsing the source, each block of code is usually explained in the paragraphs immediately preceeding or following it.

This engine is still under active development, and errors in the code are likely present.
Issues may be submitted through [GitHub](https://github.com/literallybenjam/jelli/issues) should any bugs be discovered.

###  Document structure:  ###

Each source file is split into two main parts.
The first, titled "Introduction", outlines and documents the features of the module and how to use them.
The second, titled "Implementation", provides and explains the source code of the module.
Readers looking to use the engine need largely only concern themselves with the first section, but readers aiming for a deeper understanding of how the engine operates should read both.

###  Formatting conventions:  ###

Source files are written in GitHub-Flavored Markdown (GFM), utilizing fenced code-blocks for non-compiled source and the occasional table.

This is a paragraph.
It is in a section titled “Formatting conventions”.
In the Markdown source, each sentence is given its own line.
Variable names, literals, and code excerpts are represented like `this`, whereas `this()` is a function and `<this>` is an element.
This is *emphasis*, and this is **important**.
Here is a [link](http://example.com).

- This is a short unordered list
- In the source, there is minimal padding between and around lines

>   **Note :**
    This is a note.

1.  This is an ordered list
2.  Here is item #2
3.  Short list items like these don't end in periods

>   [Issue ##](https://github.com/literallybenjam/jelli/issues) :
This is a note regarding a known issue.

-   This is an unordered list with paragraph content.
    For these kinds of lists, there is more padding in the source and each sentence ends with a period.

-   Although this is an unordered list, an ordered list with paragraph content would be formatted in much the same way.

>   ```coffeescript
>   "This is a sample block of CoffeeScript code.
>   It will not appear in the compiled source."
>   ```

>   ```html
>   <!DOCTYPE html>
>   <p>And here is a block of HTML.</p>
>   ```

This is a line break:

- - -

The CoffeeScript source uses four spaces for indentation.
This aids in visually matching up lines when several paragraphs of text lie between them.

The following is a subsection titled “Case conventions and variable names”.

####  Case conventions and variable names  ####

Variables are named as follows:

- `snake_case` is used for variable and property names.
- `SCREAMING_SNAKE_CASE` is used for symbols and special static values.
- `camelCase` is used for function names
- `PascalCase` (`UpperCamelCase`) is used for object constructors.

Class names are written in `RUNNINGCAPS`.
This is intended to mirror the style of `Element.tagName`, as well as distinguish them from user-defined classes (which presumably are lower- or mixed-case).
Note that HTML class names are, by spec, **not** case-insensitive, and thus the all-caps representation is **required**.

Tag names are written lower-case and wrapped in less-than and greater-than signs.
This distinguishes elements specified by `<tagname>` and elements specified by `CLASS`.
Elements may also be referred to by the DOM interface they implement; for example, `<img>` may be referred to as `HTMLImageElement` when this better reflects the code.

With `data-*` attributes, `runningtext` is used for variable names, but these are *often* given hyphen-separated semantic prefixes.
So you will have `data-bitdepth` but also `data-sprite-width`.
In JavaScript, these become `dataset.bitdepth` and `dataset.spriteWidth`, respectively.

##  Implementation  ##

    "use strict";

    ###
    THE JELLI GAME ENGINE
    Programmed by Margaret Russel
    -----------------------------
    Implemented through several modules in Literate CoffeeScript.
    Source code and resources are available at https://github.com/literallybenjam/jelli/.
    Written for the CoffeeScript 1.10.0 compiler.
    ###

###  License:  ###

The Jelli Game Engine is licensed under an MIT License, provided below:

    ###
    MIT License

    Copyright (c) 2016 Margaret Russel

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE.
    ###

###  Usage:  ###

Simply include [`jelli.js`](../jelli.js) in the `<head>` of your document to load the script.

    ###
    How To Use:

    The `Game` constructor creates a new game, which is automatically assigned to `document.game`.
    You can choose a different document for game rendering by passing it in as an attribute.
    A document can have only one game assigned to it at a time, and this game is non-configurable.

    A sample loading script might look like this:

        window.addEventListener("load", function () {new Game(document);}, false);
    ###

#  THE JELLI GAME ENGINE  #
Programmed by Margaret Russel

- - -

##  Introduction  ##

This folder contains all of the source code for the Jelli Game Engine.
Jelli is written in Literate CoffeeScript, which means that each source file can be read as Markdown.
The code blocks (indented with four spaces) in each file are the CoffeeScript code.
This file is the [`README`](README.litcoffee), and is, in fact, a file in the engine's source.

####  Browser compatibility  ####

The anticipated (ie, untested) browser compatibility for the Jelli Game Engine and its various modules is as follows:

| Chrome | Firefox | Internet Explorer | Opera | Safari |
| :----: | :-----: | :---------------: | :---: | :----: |
|    7   |   4.0   |         9         |   12  |   5.1  |

A few specific features have higher requirements, however:

#####  touch events  #####

Touch events are often either not supported or hidden behind a preference on desktop browsers.
In addition, touch events on IE mobile is only supported after version 11 with Windows Phone 8.1.

#####  mouse events  #####

Mouse events likewise have higher requirements, due to the engine's dependence on `MouseEvent.pageX` and `MouseEvent.pageY`.
This is supported in all major browsers, but may not work in more antiquated ones (for example, Chrome requires at least version 45).

#####  pixelated images  #####

The Jelli Game Engine currently handles canvas upscaling using CSS to create a pixelated appearance.
This feature is only supported in recent browsers, so older ones may display a blurry image on larger screens.

##### additional notes  #####

Not all browsers will act the same way when multiple elements share the same `id` or `name`.
Non–Gecko-based browsers do not conform with the spec for `HTMLCollection.namedItem()` in these instances and will likely break the script.
Of course, giving multiple elements the same `id` is bad practice anyway, so this is unlikely to pose an issue.

Safari (including on iOS) can sometimes fail to properly clear the canvas in select instances, for reasons that escape me and are likely a bug in Safari code.
(In one instance, one canvas would only clear if a *different* canvas was set to clear on area change, regardless of whether area change actually ever occurred.
I really have no solution to this except mess around until you can get things to work.)

###  Modules:  ###

The Jelli Game Engine depends upon, and is developed alongside, several modules, each seperately encapsulated for portability and reusability.
The modules at this time are:

- [`Screen`](modules/Screen.litcoffee)
- [`Control`](modules/Control.litcoffee)
- [`Poke`](modules/Poke.litcoffee)
- [`Sheet`](modules/Sheet.litcoffee)
- [`Letters`](modules/Letters.litcoffee)
- [`Tileset`](modules/Tileset.litcoffee)

>   [Issue #51](https://github.com/literallybenjam/jelli/issues/51) :
    Support for a `Filter` module is also planned.

You can view the source for each module by viewing the appropriately named `.litcoffee` file in the [modules](modules) directory.

###  Engine:  ###

The game engine, which depends on the aformentioned modules, is itself modular, comprised of a number of interdependent components.
At this time, the list of these components is as follows:

1. [`Jelli`](engine/01 Jelli.litcoffee)
2. [`Game`](engine/02 Game.litcoffee)
3. [`Area`](engine/03 Area.litcoffee)
4. [`Collection`](engine/04 Collection.litcoffee)
5. [`Unit`](engine/05 Unit.litcoffee)
6. [`PlacementImage`](engine/06 PlacementImage.litcoffee)
7. [`Character`](engine/07 Character.litcoffee)

Documentation for each engine module is available in the [engine](engine) directory.

###  How to read this engine:  ###

The best starting point for most readers and developers is reading through the documentation files for the engine itself, starting with the [`Introduction`](engine/00 Introduction.litcoffee), as these provide all of the interfaces necessary for game development.
Nevertheless, the engine relies on the other modules for many of its tasks, and will reference them from time to time.
A policy of focusing on the engine and looking up the other modules when needed is probably the best approach to becoming familiar with the system as a whole.

It is not necessary to understand the code behind this engine in order to put it into use.
In fact, the extensive documentation provided for the engine exists precisely to make it accessible without forcing users to dig through code.
When browsing the source, each block of code is usually explained in the paragraphs immediately preceeding or following it.

This engine is still under active development, and errors in the code are likely present.
Issues may be submitted through [GitHub](https://github.com/literallybenjam/jelli/issues) should any bugs be discovered.

###  Document structure:  ###

Each source file is split into two main parts.
The first, titled "Introduction", outlines and documents the features of the module and how to use them.
The second, titled "Implementation", provides and explains the source code of the module.
Readers looking to use the engine need largely only concern themselves with the first section, but readers aiming for a deeper understanding of how the engine operates should read both.

###  Formatting conventions:  ###

Source files are written in GitHub-Flavored Markdown (GFM), utilizing fenced code-blocks for non-compiled source and the occasional table.

This is a paragraph.
It is in a section titled “Formatting conventions”.
In the Markdown source, each sentence is given its own line.
Variable names, literals, and code excerpts are represented like `this`, whereas `this()` is a function and `<this>` is an element.
This is *emphasis*, and this is **important**.
Here is a [link](http://example.com).

- This is a short unordered list
- In the source, there is minimal padding between and around lines

>   **Note :**
    This is a note.

1.  This is an ordered list
2.  Here is item #2
3.  Short list items like these don't end in periods

>   [Issue ##](https://github.com/literallybenjam/jelli/issues) :
This is a note regarding a known issue.

-   This is an unordered list with paragraph content.
    For these kinds of lists, there is more padding in the source and each sentence ends with a period.

-   Although this is an unordered list, an ordered list with paragraph content would be formatted in much the same way.

>   ```coffeescript
>   "This is a sample block of CoffeeScript code.
>   It will not appear in the compiled source."
>   ```

>   ```html
>   <!DOCTYPE html>
>   <p>And here is a block of HTML.</p>
>   ```

This is a line break:

- - -

The CoffeeScript source uses four spaces for indentation.
This aids in visually matching up lines when several paragraphs of text lie between them.

The following is a subsection titled “Case conventions and variable names”.

####  Case conventions and variable names  ####

Variables are named as follows:

- `snake_case` is used for variable and property names.
- `SCREAMING_SNAKE_CASE` is used for symbols and special static values.
- `camelCase` is used for function names
- `PascalCase` (`UpperCamelCase`) is used for object constructors.

Class names are written in `RUNNINGCAPS`.
This is intended to mirror the style of `Element.tagName`, as well as distinguish them from user-defined classes (which presumably are lower- or mixed-case).
Note that HTML class names are, by spec, **not** case-insensitive, and thus the all-caps representation is **required**.

Tag names are written lower-case and wrapped in less-than and greater-than signs.
This distinguishes elements specified by `<tagname>` and elements specified by `CLASS`.
Elements may also be referred to by the DOM interface they implement; for example, `<img>` may be referred to as `HTMLImageElement` when this better reflects the code.

With `data-*` attributes, `runningtext` is used for variable names, but these are *often* given hyphen-separated semantic prefixes.
So you will have `data-bitdepth` but also `data-sprite-width`.
In JavaScript, these become `dataset.bitdepth` and `dataset.spriteWidth`, respectively.

##  Implementation  ##

    "use strict";

    ###
    THE JELLI GAME ENGINE
    Programmed by Margaret Russel
    -----------------------------
    Implemented through several modules in Literate CoffeeScript.
    Source code and resources are available at https://github.com/literallybenjam/jelli/.
    Written for the CoffeeScript 1.10.0 compiler.
    ###

###  License:  ###

The Jelli Game Engine is licensed under an MIT License, provided below:

    ###
    MIT License

    Copyright (c) 2016 Margaret Russel

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE.
    ###

###  Usage:  ###

Simply include [`jelli.js`](../jelli.js) in the `<head>` of your document to load the script.

    ###
    How To Use:

    The `Game` constructor creates a new game, which is automatically assigned to `document.game`.
    You can choose a different document for game rendering by passing it in as an attribute.
    A document can have only one game assigned to it at a time, and this game is non-configurable.

    A sample loading script might look like this:

        window.addEventListener("load", function () {new Game(document);}, false);
    ###