You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by pm...@apache.org on 2014/09/04 14:37:17 UTC

[15/15] weinre commit: pre-compile CoffeeScript files in server

pre-compile CoffeeScript files in server


Project: http://git-wip-us.apache.org/repos/asf/cordova-weinre/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-weinre/commit/03084bdb
Tree: http://git-wip-us.apache.org/repos/asf/cordova-weinre/tree/03084bdb
Diff: http://git-wip-us.apache.org/repos/asf/cordova-weinre/diff/03084bdb

Branch: refs/heads/master
Commit: 03084bdb6a23cc4f6085a16420df9182b2252e43
Parents: 34d2980
Author: Patrick Mueller <pm...@apache.org>
Authored: Sat Aug 30 14:42:05 2014 -0400
Committer: Patrick Mueller <pm...@apache.org>
Committed: Thu Sep 4 08:35:08 2014 -0400

----------------------------------------------------------------------
 .wr                                             |    2 +-
 weinre.build/build.xml                          |   21 +
 weinre.build/package.json.template              |   10 +-
 weinre.server/lib-src/Channel.coffee            |  118 +
 weinre.server/lib-src/HttpChannelHandler.coffee |  154 ++
 weinre.server/lib-src/MessageQueue.coffee       |   87 +
 weinre.server/lib-src/channelManager.coffee     |  126 ++
 weinre.server/lib-src/cli.coffee                |  130 ++
 weinre.server/lib-src/dumpingHandler.coffee     |   77 +
 weinre.server/lib-src/extensionManager.coffee   |   30 +
 weinre.server/lib-src/jsonBodyParser.coffee     |   47 +
 weinre.server/lib-src/messageHandler.coffee     |   59 +
 .../lib-src/service/WeinreClientCommands.coffee |  126 ++
 .../lib-src/service/WeinreTargetCommands.coffee |   90 +
 weinre.server/lib-src/serviceManager.coffee     |   95 +
 weinre.server/lib-src/utils.coffee              |  196 ++
 weinre.server/lib-src/weinre.coffee             |  186 ++
 weinre.server/lib/Channel.coffee                |  118 -
 weinre.server/lib/Channel.js                    |  130 ++
 weinre.server/lib/HttpChannelHandler.coffee     |  154 --
 weinre.server/lib/HttpChannelHandler.js         |  130 ++
 weinre.server/lib/MessageQueue.coffee           |   87 -
 weinre.server/lib/MessageQueue.js               |   82 +
 weinre.server/lib/channelManager.coffee         |  126 --
 weinre.server/lib/channelManager.js             |  122 +
 weinre.server/lib/cli.coffee                    |  130 --
 weinre.server/lib/cli.js                        |   97 +
 weinre.server/lib/dumpingHandler.coffee         |   77 -
 weinre.server/lib/dumpingHandler.js             |   74 +
 weinre.server/lib/extensionManager.coffee       |   30 -
 weinre.server/lib/extensionManager.js           |   15 +
 weinre.server/lib/jsonBodyParser.coffee         |   47 -
 weinre.server/lib/jsonBodyParser.js             |   39 +
 weinre.server/lib/messageHandler.coffee         |   59 -
 weinre.server/lib/messageHandler.js             |   51 +
 .../lib/service/WeinreClientCommands.coffee     |  126 --
 .../lib/service/WeinreClientCommands.js         |  140 ++
 .../lib/service/WeinreTargetCommands.coffee     |   90 -
 .../lib/service/WeinreTargetCommands.js         |   78 +
 weinre.server/lib/serviceManager.coffee         |   95 -
 weinre.server/lib/serviceManager.js             |   90 +
 weinre.server/lib/utils.coffee                  |  196 --
 weinre.server/lib/utils.js                      |  194 ++
 weinre.server/lib/weinre.coffee                 |  186 --
 weinre.server/lib/weinre.js                     |  193 ++
 weinre.server/node_modules/.bin/cake            |    2 +-
 weinre.server/node_modules/.bin/coffee          |    2 +-
 weinre.server/node_modules/.bin/express         |    2 +-
 weinre.server/node_modules/.bin/nopt            |    2 +-
 .../node_modules/coffee-script/CONTRIBUTING.md  |    9 +
 .../node_modules/coffee-script/LICENSE          |    4 +-
 weinre.server/node_modules/coffee-script/README |   21 +-
 .../node_modules/coffee-script/README.md        |   60 +
 .../node_modules/coffee-script/Rakefile         |   78 -
 .../node_modules/coffee-script/extras/jsl.conf  |   44 -
 .../coffee-script/lib/coffee-script/browser.js  |  100 +-
 .../coffee-script/lib/coffee-script/cake.js     |   11 +-
 .../lib/coffee-script/coffee-script.js          |  296 ++-
 .../coffee-script/lib/coffee-script/command.js  |  554 +++--
 .../coffee-script/lib/coffee-script/grammar.js  |   79 +-
 .../coffee-script/lib/coffee-script/helpers.js  |  181 +-
 .../coffee-script/lib/coffee-script/index.js    |    2 +-
 .../coffee-script/lib/coffee-script/lexer.js    |  412 ++--
 .../coffee-script/lib/coffee-script/nodes.js    | 1578 +++++++------
 .../coffee-script/lib/coffee-script/optparse.js |    9 +-
 .../coffee-script/lib/coffee-script/parser.js   |  753 ++++---
 .../coffee-script/lib/coffee-script/register.js |   66 +
 .../coffee-script/lib/coffee-script/repl.js     |  381 ++--
 .../coffee-script/lib/coffee-script/rewriter.js |  402 ++--
 .../coffee-script/lib/coffee-script/scope.js    |    6 +-
 .../lib/coffee-script/sourcemap.js              |  161 ++
 .../node_modules/mkdirp/.npmignore              |    2 +
 .../node_modules/mkdirp/.travis.yml             |    5 +
 .../coffee-script/node_modules/mkdirp/LICENSE   |   21 +
 .../node_modules/mkdirp/examples/pow.js         |    6 +
 .../coffee-script/node_modules/mkdirp/index.js  |   82 +
 .../node_modules/mkdirp/package.json            |   34 +
 .../node_modules/mkdirp/readme.markdown         |   63 +
 .../node_modules/mkdirp/test/chmod.js           |   38 +
 .../node_modules/mkdirp/test/clobber.js         |   37 +
 .../node_modules/mkdirp/test/mkdirp.js          |   28 +
 .../node_modules/mkdirp/test/perm.js            |   32 +
 .../node_modules/mkdirp/test/perm_sync.js       |   39 +
 .../node_modules/mkdirp/test/race.js            |   41 +
 .../node_modules/mkdirp/test/rel.js             |   32 +
 .../node_modules/mkdirp/test/return.js          |   25 +
 .../node_modules/mkdirp/test/return_sync.js     |   24 +
 .../node_modules/mkdirp/test/root.js            |   18 +
 .../node_modules/mkdirp/test/sync.js            |   32 +
 .../node_modules/mkdirp/test/umask.js           |   28 +
 .../node_modules/mkdirp/test/umask_sync.js      |   32 +
 .../node_modules/coffee-script/package.json     |   38 +-
 .../node_modules/coffee-script/register.js      |    1 +
 .../node_modules/coffee-script/repl.js          |    1 +
 weinre.server/node_modules/express/History.md   |    5 +
 .../node_modules/express/lib/express.js         |    2 +-
 .../node_modules/express/lib/request.js         |   23 +-
 .../express/node_modules/connect/lib/connect.js |    2 +-
 .../node_modules/connect/lib/middleware/csrf.js |    2 +-
 .../connect/node_modules/formidable/.npmignore  |    5 +-
 .../connect/node_modules/formidable/.travis.yml |    5 +-
 .../connect/node_modules/formidable/LICENSE     |    7 +
 .../connect/node_modules/formidable/Makefile    |   14 -
 .../connect/node_modules/formidable/Readme.md   |  468 ++--
 .../connect/node_modules/formidable/TODO        |    3 -
 .../benchmark/bench-multipart-parser.js         |   70 -
 .../node_modules/formidable/example/post.js     |   43 -
 .../node_modules/formidable/example/upload.js   |   48 -
 .../connect/node_modules/formidable/index.js    |    2 +-
 .../connect/node_modules/formidable/lib/file.js |   45 +-
 .../formidable/lib/incoming_form.js             |  285 ++-
 .../node_modules/formidable/lib/json_parser.js  |   35 +
 .../formidable/lib/multipart_parser.js          |   50 +-
 .../node_modules/formidable/lib/octet_parser.js |   20 +
 .../formidable/lib/querystring_parser.js        |   10 +-
 .../connect/node_modules/formidable/lib/util.js |    6 -
 .../formidable/node-gently/Makefile             |    4 -
 .../formidable/node-gently/Readme.md            |  167 --
 .../formidable/node-gently/example/dog.js       |   22 -
 .../node-gently/example/event_emitter.js        |   11 -
 .../formidable/node-gently/index.js             |    1 -
 .../formidable/node-gently/lib/gently/gently.js |  184 --
 .../formidable/node-gently/lib/gently/index.js  |    1 -
 .../formidable/node-gently/package.json         |   14 -
 .../formidable/node-gently/test/common.js       |    8 -
 .../node-gently/test/simple/test-gently.js      |  348 ---
 .../node_modules/formidable/package.json        |   27 +-
 .../node_modules/formidable/test/common.js      |   19 -
 .../test/fixture/file/funkyfilename.txt         |    1 -
 .../formidable/test/fixture/file/plain.txt      |    1 -
 .../http/special-chars-in-filename/info.md      |    3 -
 .../formidable/test/fixture/js/no-filename.js   |    3 -
 .../fixture/js/special-chars-in-filename.js     |   21 -
 .../formidable/test/fixture/multipart.js        |   72 -
 .../test/integration/test-fixtures.js           |   89 -
 .../formidable/test/legacy/common.js            |   24 -
 .../legacy/integration/test-multipart-parser.js |   80 -
 .../formidable/test/legacy/simple/test-file.js  |  104 -
 .../test/legacy/simple/test-incoming-form.js    |  727 ------
 .../test/legacy/simple/test-multipart-parser.js |   50 -
 .../legacy/simple/test-querystring-parser.js    |   45 -
 .../legacy/system/test-multi-video-upload.js    |   75 -
 .../connect/node_modules/formidable/test/run.js |    2 -
 .../formidable/test/unit/test-incoming-form.js  |   63 -
 .../node_modules/formidable/tool/record.js      |   47 -
 .../express/node_modules/connect/package.json   |    9 +-
 .../express/node_modules/connect/test.js        |   39 +-
 .../express/node_modules/mime/package.json      |   10 +-
 .../express/node_modules/mkdirp/package.json    |    8 +-
 .../express/node_modules/qs/package.json        |    6 +
 weinre.server/node_modules/express/package.json |   10 +-
 weinre.server/node_modules/express/test.js      |    3 +
 weinre.server/node_modules/nopt/.npmignore      |    1 +
 weinre.server/node_modules/nopt/README.md       |   15 +-
 weinre.server/node_modules/nopt/bin/nopt.js     |   14 +-
 weinre.server/node_modules/nopt/lib/nopt.js     |  282 +--
 .../nopt/node_modules/abbrev/CONTRIBUTING.md    |    3 +
 .../nopt/node_modules/abbrev/LICENSE            |   23 +
 .../nopt/node_modules/abbrev/abbrev.js          |   62 +
 .../nopt/node_modules/abbrev/lib/abbrev.js      |  106 -
 .../nopt/node_modules/abbrev/package.json       |   17 +-
 .../nopt/node_modules/abbrev/test.js            |   47 +
 weinre.server/node_modules/nopt/package.json    |   18 +-
 weinre.server/node_modules/nopt/test/basic.js   |  251 +++
 .../node_modules/underscore/.npmignore          |    3 -
 weinre.server/node_modules/underscore/CNAME     |    1 -
 weinre.server/node_modules/underscore/LICENSE   |    5 +-
 weinre.server/node_modules/underscore/README.md |   25 +-
 .../node_modules/underscore/favicon.ico         |  Bin 1406 -> 0 bytes
 .../node_modules/underscore/index.html          | 2109 ------------------
 weinre.server/node_modules/underscore/index.js  |    1 -
 .../node_modules/underscore/package.json        |   38 +-
 .../node_modules/underscore/raw/underscore.psd  |  Bin 215540 -> 0 bytes
 .../node_modules/underscore/underscore-min.js   |   38 +-
 .../node_modules/underscore/underscore.js       | 1390 +++++++-----
 weinre.server/weinre                            |   11 +-
 176 files changed, 8950 insertions(+), 9342 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-weinre/blob/03084bdb/.wr
----------------------------------------------------------------------
diff --git a/.wr b/.wr
index 265dd0a..caf5fe6 100644
--- a/.wr
+++ b/.wr
@@ -7,7 +7,7 @@ weinre.build/scripts
 
 weinre.doc
 weinre.server/interfaces
-weinre.server/lib
+weinre.server/lib-src
 weinre.server/package.json
 weinre.server/README.md
 

http://git-wip-us.apache.org/repos/asf/cordova-weinre/blob/03084bdb/weinre.build/build.xml
----------------------------------------------------------------------
diff --git a/weinre.build/build.xml b/weinre.build/build.xml
index 5324454..17f58d5 100644
--- a/weinre.build/build.xml
+++ b/weinre.build/build.xml
@@ -174,6 +174,7 @@ To update the weinre dependencies, use
             >git: ${git-log}
 </concat> <!-- keep this outdented, since Ant is so wonderful -->
 
+        <antcall target="build-server"/>
         <antcall target="build-web"/>
         <antcall target="build-json-idl"/>
         <antcall target="build-client"/>
@@ -202,6 +203,26 @@ To update the weinre dependencies, use
     </target>
 
     <!-- ============================================================
+         basic server resources
+         ============================================================ -->
+
+    <target name="build-server">
+        <delete dir="../${PROJECT_SERVER}/lib" />
+        <mkdir  dir="../${PROJECT_SERVER}/lib" />
+        <mkdir  dir="../${PROJECT_SERVER}/lib/service" />
+
+        <echo message="compiling CoffeeScript files in: ${PROJECT_SERVER}/lib-src"/>
+        <exec executable="node" failonerror="true" failifexecutionfails="true">
+            <arg value="../${PROJECT_SERVER}/node_modules/coffee-script/bin/coffee"/>
+            <arg value="--compile"/>
+            <arg value="--bare"/>
+            <arg value="--output"/>
+            <arg value="../${PROJECT_SERVER}/lib"/>
+            <arg value="../${PROJECT_SERVER}/lib-src"/>
+        </exec>
+    </target>
+
+    <!-- ============================================================
          basic web resources
          ============================================================ -->
 

http://git-wip-us.apache.org/repos/asf/cordova-weinre/blob/03084bdb/weinre.build/package.json.template
----------------------------------------------------------------------
diff --git a/weinre.build/package.json.template b/weinre.build/package.json.template
index 71f3762..1779836 100644
--- a/weinre.build/package.json.template
+++ b/weinre.build/package.json.template
@@ -21,10 +21,13 @@
     },
   "dependencies":
     {
-      "coffee-script": "1.3.x",
       "express":       "2.5.x",
-      "nopt":          "1.0.x",
-      "underscore":    "1.3.x"
+      "nopt":          "3.0.x",
+      "underscore":    "1.7.x"
+    },
+  "devDependencies":
+    {
+      "coffee-script": "1.8.x"
     },
   "main" :             "./lib/weinre",
   "bin":
@@ -39,4 +42,3 @@
       "url":           "https://git-wip-us.apache.org/repos/asf/cordova-weinre.git"
     }
 }
-

http://git-wip-us.apache.org/repos/asf/cordova-weinre/blob/03084bdb/weinre.server/lib-src/Channel.coffee
----------------------------------------------------------------------
diff --git a/weinre.server/lib-src/Channel.coffee b/weinre.server/lib-src/Channel.coffee
new file mode 100644
index 0000000..70f5841
--- /dev/null
+++ b/weinre.server/lib-src/Channel.coffee
@@ -0,0 +1,118 @@
+#-------------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#-------------------------------------------------------------------------------
+
+_ = require 'underscore'
+
+utils          = require './utils'
+channelManager = require './channelManager'
+messageHandler = require './messageHandler'
+MessageQueue   = require './MessageQueue'
+
+AnonymousId = 'anonymous'
+
+#-------------------------------------------------------------------------------
+module.exports = utils.registerClass class Channel
+    
+    #---------------------------------------------------------------------------
+    constructor: (@pathPrefix, @id, @remoteAddress, @isClient) ->
+        prefix         = if @isClient then 'c-' else 't-'
+        @name          = "#{prefix}#{utils.getNextSequenceNumber()}"
+        @messageQueue  = new MessageQueue
+        @isClosed      = false
+        @connections   = []
+        @isTarget      = !@isClient
+        @readTimeout   = utils.options.readTimeout * 1000
+        
+        @id = AnonymousId if !@id 
+        
+        @description = 
+            channel:       @name
+            id:            @id
+            hostName:      @remoteAddress
+            remoteAddress: @remoteAddress
+        
+        @updateLastRead()
+
+        channelManager.created @
+
+    #---------------------------------------------------------------------------
+    close: () ->
+        return if @isClosed
+        
+        channelManager.destroyed @
+        
+        @isClosed = true
+        @messageQueue.shutdown()
+
+    #---------------------------------------------------------------------------
+    sendCallback: (intfName, callbackId, args...) ->
+        return if !callbackId
+        
+        args.unshift callbackId
+        
+        @sendMessage intfName, 'sendCallback', args...
+        
+    #---------------------------------------------------------------------------
+    sendMessage: (intfName, method, args...) ->
+
+        message = genJSON
+            interface: intfName
+            method:    method
+            args:      args
+        
+        @messageQueue.push message
+
+    #---------------------------------------------------------------------------
+    handleMessages: (messages) ->
+
+        for message in messages
+            message = parseJSON(message)
+            continue if !message
+            
+            messageHandler.handleMessage @, message
+        
+    #---------------------------------------------------------------------------
+    getMessages: (callback) ->
+        @updateLastRead()
+        return callback.call(null, null) if @isClosed
+        
+        @messageQueue.pullAll @readTimeout, callback
+        
+    #---------------------------------------------------------------------------
+    updateLastRead: () ->
+        @lastRead = (new Date).valueOf()
+
+    #---------------------------------------------------------------------------
+    toString: () ->
+        connections = _.map(@connections, (val) -> val.name).join(',')
+        "Channel(#{@name}, closed:#{@isClosed}, connections:[#{connections}])"
+
+#-------------------------------------------------------------------------------
+parseJSON = (message) ->
+    try 
+        return JSON.parse(message)
+    catch e
+        return null
+
+#-------------------------------------------------------------------------------
+genJSON = (message) ->
+    try 
+        return JSON.stringify(message)
+    catch e
+        return null

http://git-wip-us.apache.org/repos/asf/cordova-weinre/blob/03084bdb/weinre.server/lib-src/HttpChannelHandler.coffee
----------------------------------------------------------------------
diff --git a/weinre.server/lib-src/HttpChannelHandler.coffee b/weinre.server/lib-src/HttpChannelHandler.coffee
new file mode 100644
index 0000000..dd7f2f4
--- /dev/null
+++ b/weinre.server/lib-src/HttpChannelHandler.coffee
@@ -0,0 +1,154 @@
+#-------------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#-------------------------------------------------------------------------------
+
+_ = require 'underscore'
+
+utils          = require './utils'
+Channel        = require './Channel'
+channelManager = require './channelManager'
+
+#-------------------------------------------------------------------------------
+module.exports = utils.registerClass class HttpChannelHandler
+
+    #---------------------------------------------------------------------------
+    constructor: (@pathPrefix) ->
+    
+        if @pathPrefix == '/ws/client'
+            @isClient = true
+            
+        else if @pathPrefix == '/ws/target'
+            @isClient = false
+            
+        else
+            utils.pitch "invalid pathPrefix: #{@pathPrefix}"
+            
+        @isTarget = !@isClient
+        
+    #---------------------------------------------------------------------------
+    handle: (request, response, uri) ->
+    
+        setCORSHeaders  request, response
+        setCacheHeaders request, response
+
+        #-----------------
+        
+        # * #{pathPrefix}a
+        if uri[0] != '/'
+            return handleError(request, response, 404)
+            
+        #-----------------
+        
+        if uri == '/'
+        
+            # OPTIONS #{pathPrefix}/
+            if request.method == 'OPTIONS'
+                return handleOptions(request, response)
+
+            # POST #{pathPrefix}/
+            if request.method == 'POST'
+                return handleCreate(@pathPrefix, @isClient, request, response)
+                
+            # * #{pathPrefix}/
+            return handleError(request, response, 405)
+            
+        #-----------------
+            
+        parts = uri.split('/')
+        
+        # * #{pathPrefix}/x/y
+        if parts.length > 2
+            return handleError(request, response, 404)
+
+        #-----------------
+        
+        channelName = parts[1]
+        
+        # OPTIONS #{pathPrefix}/x
+        if request.method == 'OPTIONS'
+            return handleOptions(request, response)
+
+        # GET #{pathPrefix}/x
+        if request.method == 'GET'
+            return handleGet(request, response, channelName)
+        
+        # POST #{pathPrefix}/x
+        if request.method == 'POST'
+            return handlePost(request, response, channelName)
+        
+        # anything else
+        return handleError(request, response, 405)
+
+#-------------------------------------------------------------------------------
+handleCreate = (pathPrefix, isClient, request, response) ->
+    id = request.body?.id
+    
+    remoteAddress = request.connection?.remoteAddress || ""
+    
+    channel = new Channel(pathPrefix, id, remoteAddress, isClient)
+    
+    response.contentType 'application/json'
+    response.send JSON.stringify
+        channel: channel.name
+        id:      channel.id
+
+#-------------------------------------------------------------------------------
+handleGet = (request, response, channelName) ->
+    remoteAddress = request.connection?.remoteAddress || ""
+    channel       = channelManager.getChannel(channelName, remoteAddress)
+    return handleError(request, response, 404) if !channel
+    
+    channel.getMessages (messages) => 
+        return handleError(request, response, 404) if channel.isClosed
+        return handleError(request, response, 404) if !messages
+        
+        response.contentType 'application/json'
+        response.send JSON.stringify(messages)
+
+#-------------------------------------------------------------------------------
+handlePost = (request, response, channelName) ->
+    remoteAddress = request.connection?.remoteAddress || ""
+    channel       = channelManager.getChannel(channelName, remoteAddress)
+    return handleError(request, response, 404) if !channel
+    
+    channel.handleMessages(request.body)
+    response.send('')
+
+#-------------------------------------------------------------------------------
+handleOptions = (request, response) ->
+    response.send('')
+
+#-------------------------------------------------------------------------------
+handleError = (request, response, status) ->
+    response.send(status)
+
+#-------------------------------------------------------------------------------
+setCORSHeaders = (request, response) ->
+    origin = request.header 'Origin'
+    return if !origin
+    
+    response.header 'Access-Control-Allow-Origin',  origin
+    response.header 'Access-Control-Max-Age',       '600'
+    response.header 'Access-Control-Allow-Methods', 'GET, POST'
+
+#-------------------------------------------------------------------------------
+setCacheHeaders = (request, response) ->
+    response.header 'Pragma',        'no-cache'
+    response.header 'Expires',       '0'
+    response.header 'Cache-Control', 'no-cache'
+    response.header 'Cache-Control', 'no-store'

http://git-wip-us.apache.org/repos/asf/cordova-weinre/blob/03084bdb/weinre.server/lib-src/MessageQueue.coffee
----------------------------------------------------------------------
diff --git a/weinre.server/lib-src/MessageQueue.coffee b/weinre.server/lib-src/MessageQueue.coffee
new file mode 100644
index 0000000..52af9ea
--- /dev/null
+++ b/weinre.server/lib-src/MessageQueue.coffee
@@ -0,0 +1,87 @@
+#-------------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#-------------------------------------------------------------------------------
+
+_ = require 'underscore'
+
+utils = require './utils'
+
+#-------------------------------------------------------------------------------
+module.exports = utils.registerClass class MessageQueue
+
+    #---------------------------------------------------------------------------
+    constructor: () ->
+        @messages     = []
+        @closed       = false
+        @callback     = null
+        @timer        = null
+        
+        _.bindAll @, '_timerExpired', '_updated'
+        
+    #---------------------------------------------------------------------------
+    shutdown: () ->
+        return if @closed
+
+        @closed = true
+
+        clearTimeout @timer if @timer
+        @callback.call(null, @messages) if @callback
+        
+        @callback = null
+        @messages = null 
+        @timer    = null
+    
+    #---------------------------------------------------------------------------
+    push: (message) ->
+        return if @closed
+        
+        @messages.push message
+        process.nextTick @_updated
+
+    #---------------------------------------------------------------------------
+    pullAll: (timeout, callback) ->
+        return callback.call(null, null) if @closed
+        return callback.call(null, [])   if @callback
+        
+        if @messages.length
+            callback.call(null, @messages)
+            @messages = []
+            return
+        
+        @callback = callback
+        @timer    = setTimeout @_timerExpired, timeout
+
+    #---------------------------------------------------------------------------
+    _timerExpired: () ->
+        @_updated()
+        
+    #---------------------------------------------------------------------------
+    _updated: () ->
+        return if @closed
+        return if !@callback
+        
+        callback = @callback
+        messages = @messages
+        clearTimeout @timer if @timer
+        
+        @callback = null
+        @messages = []
+        @timer    = null
+
+        callback.call(null, messages)      
+

http://git-wip-us.apache.org/repos/asf/cordova-weinre/blob/03084bdb/weinre.server/lib-src/channelManager.coffee
----------------------------------------------------------------------
diff --git a/weinre.server/lib-src/channelManager.coffee b/weinre.server/lib-src/channelManager.coffee
new file mode 100644
index 0000000..d55bb01
--- /dev/null
+++ b/weinre.server/lib-src/channelManager.coffee
@@ -0,0 +1,126 @@
+#-------------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#-------------------------------------------------------------------------------
+
+_  = require 'underscore'
+
+utils          = require './utils'
+serviceManager = require './serviceManager'
+
+WeinreClientEvents = null
+WeinreTargetEvents = null
+
+channelManager = null
+
+#-------------------------------------------------------------------------------
+utils.registerClass class ChannelManager
+
+    #---------------------------------------------------------------------------
+    constructor: () ->
+        @channels  = {}
+
+    #---------------------------------------------------------------------------
+    initialize: ->
+
+        WeinreClientEvents = serviceManager.get 'WeinreClientEvents'
+        WeinreTargetEvents = serviceManager.get 'WeinreTargetEvents'
+
+        if !WeinreClientEvents
+            utils.exit 'WeinreClientEvents service not registered'
+
+        if !WeinreTargetEvents
+            utils.exit 'WeinreTargetEvents service not registered'
+
+    #---------------------------------------------------------------------------
+    created: (channel) ->
+        @channels[channel.name] = channel
+
+    #---------------------------------------------------------------------------
+    destroyed: (channel) ->
+        if channel.isClient
+            for connection in channel.connections
+                @disconnectChannels(channel, connection)
+        else
+            for connection in channel.connections
+                @disconnectChannels(connection, channel)
+
+        clients = @getClientChannels(channel.id)
+
+        if channel.isClient
+            WeinreClientEvents.clientUnregistered(clients, channel.name)
+        else
+            WeinreClientEvents.targetUnregistered(clients, channel.name)
+
+        delete @channels[channel.name]
+
+    #---------------------------------------------------------------------------
+    getChannel: (name, remoteAddress) ->
+        return null if !_.has(@channels, name)
+
+        channel = @channels[name]
+
+        return null if !channel
+
+#        if remoteAddress
+#            return null if channel.remoteAddress != remoteAddress
+
+        channel
+
+    #---------------------------------------------------------------------------
+    connectChannels: (client, target) ->
+        return if client.isClosed or target.isClosed
+
+        if client.connections.length
+            @disconnectChannels(client, client.connections[0])
+
+        client.connections.push target
+        target.connections.push client
+
+        clients = @getClientChannels(client.id)
+
+        WeinreClientEvents.connectionCreated(clients, client.name, target.name)
+        WeinreTargetEvents.connectionCreated(target,  client.name, target.name)
+
+    #---------------------------------------------------------------------------
+    disconnectChannels: (client, target) ->
+
+        clients = @getClientChannels(client.id)
+
+        WeinreClientEvents.connectionDestroyed(clients, client.name, target.name)
+        WeinreTargetEvents.connectionDestroyed(target,  client.name, target.name)
+
+        client.connections = _.without(client.connections, target)
+        target.connections = _.without(target.connections, client)
+
+    #---------------------------------------------------------------------------
+    getChannels: (id) ->
+        if id?
+            _.filter(@channels, (item) -> item.id == id)
+        else
+            _.values(@channels)
+
+    #---------------------------------------------------------------------------
+    getClientChannels: (id) ->
+        _.filter(@channels, (item) -> item.isClient && item.id == id)
+
+    #---------------------------------------------------------------------------
+    getTargetChannels: (id) ->
+        _.filter(@channels, (item) -> item.isTarget && item.id == id)
+
+#-------------------------------------------------------------------------------
+module.exports = new ChannelManager

http://git-wip-us.apache.org/repos/asf/cordova-weinre/blob/03084bdb/weinre.server/lib-src/cli.coffee
----------------------------------------------------------------------
diff --git a/weinre.server/lib-src/cli.coffee b/weinre.server/lib-src/cli.coffee
new file mode 100644
index 0000000..197e39c
--- /dev/null
+++ b/weinre.server/lib-src/cli.coffee
@@ -0,0 +1,130 @@
+#-------------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#-------------------------------------------------------------------------------
+
+fs   = require 'fs'
+path = require 'path'
+
+_     = require 'underscore'
+nopt  = require 'nopt'
+
+utils  = require './utils'
+weinre = require './weinre'
+
+optionDefaults =
+    httpPort:     8080
+    boundHost:    'localhost'
+    verbose:      false
+    debug:        false
+    readTimeout:  5
+
+#-------------------------------------------------------------------------------
+exports.run = ->
+
+    knownOpts =
+        httpPort:     Number
+        boundHost:    String
+        verbose:      Boolean
+        debug:        Boolean
+        readTimeout:  Number
+        deathTimeout: Number
+        help:         Boolean
+
+    shortHands =
+        '?':  ['--help']
+        'h':  ['--help']
+
+    nopt.invalidHandler = printNoptError
+    parsedOpts = nopt(knownOpts, shortHands, process.argv, 2)
+
+    #----
+
+    printHelp() if parsedOpts.help
+
+    args = parsedOpts.argv.remain
+
+    printHelp() if args.length != 0
+
+    #----
+
+    delete parsedOpts.argv
+    opts = _.extend {}, optionDefaults, getDotWeinreServerProperties(), parsedOpts
+
+    if !opts.deathTimeout?
+        opts.deathTimeout = 3 * opts.readTimeout
+
+    utils.setOptions opts
+
+    weinre.run opts
+
+#-------------------------------------------------------------------------------
+printNoptError = (key, val, types) ->
+    utils.exit "error with option '#{key}', value '#{val}'"
+
+#-------------------------------------------------------------------------------
+printHelp = () ->
+    version = weinre.getVersion()
+
+    console.error """
+usage:   #{utils.Program} [options]
+version: #{version}
+
+options:
+    --httpPort     port to run the http server on        default: #{optionDefaults.httpPort}
+    --boundHost    ip address to bind the server to      default: #{optionDefaults.boundHost}
+    --verbose      print more diagnostics                default: #{optionDefaults.verbose}
+    --debug        print even more diagnostics           default: #{optionDefaults.debug}
+    --readTimeout  seconds to wait for a client message  default: #{optionDefaults.readTimeout}
+    --deathTimeout seconds to wait to kill client        default: 3*readTimeout
+
+--boundHost can be an ip address, hostname, or -all-, where -all-
+means binding to all ip address on the current machine'
+
+for more info see: http://people.apache.org/~pmuellr/weinre/
+"""
+    process.exit()
+
+#-------------------------------------------------------------------------------
+getDotWeinreServerProperties = () ->
+    properties = {}
+
+    fileName = replaceTilde '~/.weinre/server.properties'
+    return properties if !utils.fileExistsSync(fileName)
+
+    contents = fs.readFileSync(fileName, 'utf8')
+    lines    = contents.split('\n')
+
+    for line in lines
+        line = line.replace(/#.*/,'')
+        match = line.match /\s*(\w+)\s*:\s*(.+)\s*/
+        continue if !match
+
+        key = utils.trim match[1]
+        val = utils.trim match[2]
+
+        properties[key] = val
+
+    properties
+
+#-------------------------------------------------------------------------------
+replaceTilde = (fileName) ->
+    fileName.replace('~', getTildeReplacement())
+
+#-------------------------------------------------------------------------------
+getTildeReplacement = () ->
+    process.env["HOME"] || process.env["USERPROFILE"] || '.'

http://git-wip-us.apache.org/repos/asf/cordova-weinre/blob/03084bdb/weinre.server/lib-src/dumpingHandler.coffee
----------------------------------------------------------------------
diff --git a/weinre.server/lib-src/dumpingHandler.coffee b/weinre.server/lib-src/dumpingHandler.coffee
new file mode 100644
index 0000000..310852d
--- /dev/null
+++ b/weinre.server/lib-src/dumpingHandler.coffee
@@ -0,0 +1,77 @@
+#-------------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#-------------------------------------------------------------------------------
+
+_ = require 'underscore'
+
+utils = require './utils'
+
+#-------------------------------------------------------------------------------
+dumpingHandler = (request, response, uri) ->
+    originalSend = response.send
+    response.send = (body) ->
+        dumpResponse(originalSend, body, request, response, uri)
+    
+    return if request.method != 'POST'
+    
+    utils.logVerbose '--------------------------------------------------'
+    utils.logVerbose "#{request.method} #{uri} [request]"
+    
+    if _.isArray(request.body)
+        for element in request.body
+            utils.logVerbose "   #{enhance(JSON.parse(element))}"
+    else
+        utils.logVerbose "   #{enhance(request.body)}"
+
+#-------------------------------------------------------------------------------
+dumpResponse = (originalSend, body, request, response, uri) ->
+    originalSend.call(response, body)
+
+    return if request.method not in ['GET', 'POST']
+
+    try 
+        body = JSON.parse(body)
+    catch e
+        return
+
+    return if _.isArray(body) && (body.length == 0)
+        
+    utils.logVerbose '--------------------------------------------------'
+    utils.logVerbose "#{request.method} #{uri} #{response.statusCode} [response]"
+    
+    if _.isArray(body)
+        for element in body
+            utils.logVerbose "   #{enhance(JSON.parse(element))}"
+    else
+        utils.logVerbose "   #{enhance(body)}"
+
+#-------------------------------------------------------------------------------
+enhance = (object) ->
+    if !object.interface || !object.method || !object.args 
+        return JSON.stringify(object)
+        
+    signature = "#{object.interface}.#{object.method}"
+
+    args = JSON.stringify(object.args)
+    if args.length > 500
+        args = "#{args.substr(0,50)}..."
+    
+    return "#{signature}(#{args})"
+
+#-------------------------------------------------------------------------------
+module.exports = dumpingHandler

http://git-wip-us.apache.org/repos/asf/cordova-weinre/blob/03084bdb/weinre.server/lib-src/extensionManager.coffee
----------------------------------------------------------------------
diff --git a/weinre.server/lib-src/extensionManager.coffee b/weinre.server/lib-src/extensionManager.coffee
new file mode 100644
index 0000000..c367425
--- /dev/null
+++ b/weinre.server/lib-src/extensionManager.coffee
@@ -0,0 +1,30 @@
+#-------------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#-------------------------------------------------------------------------------
+
+utils = require './utils'
+
+#-------------------------------------------------------------------------------
+utils.registerClass class ExtensionManager
+
+    #---------------------------------------------------------------------------
+    constructor: () ->
+        @extensions = []
+    
+#-------------------------------------------------------------------------------
+module.exports = new ExtensionManager

http://git-wip-us.apache.org/repos/asf/cordova-weinre/blob/03084bdb/weinre.server/lib-src/jsonBodyParser.coffee
----------------------------------------------------------------------
diff --git a/weinre.server/lib-src/jsonBodyParser.coffee b/weinre.server/lib-src/jsonBodyParser.coffee
new file mode 100644
index 0000000..58f755b
--- /dev/null
+++ b/weinre.server/lib-src/jsonBodyParser.coffee
@@ -0,0 +1,47 @@
+#-------------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+jsonBodyParser = -> 
+    return (request, response, next) -> parseBodyAsJSON(request, response, next)
+        
+#-------------------------------------------------------------------------------
+parseBodyAsJSON = (request, response, next) ->
+
+    return next() if request.body
+    
+    request.body = {}
+    
+    return next() if request.method != 'POST'
+    
+    request.setEncoding 'utf8'
+    
+    buffer = ''
+    request.on 'data', (chunk) -> buffer += chunk
+    request.on 'end', ->
+        return next() if '' == buffer
+
+        try 
+            request.body = JSON.parse(buffer)
+            next()
+        catch e
+            next(e)
+
+#-------------------------------------------------------------------------------
+module.exports = jsonBodyParser

http://git-wip-us.apache.org/repos/asf/cordova-weinre/blob/03084bdb/weinre.server/lib-src/messageHandler.coffee
----------------------------------------------------------------------
diff --git a/weinre.server/lib-src/messageHandler.coffee b/weinre.server/lib-src/messageHandler.coffee
new file mode 100644
index 0000000..0c79430
--- /dev/null
+++ b/weinre.server/lib-src/messageHandler.coffee
@@ -0,0 +1,59 @@
+#-------------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#-------------------------------------------------------------------------------
+
+utils             = require './utils'
+channelManager    = require './channelManager'
+serviceManager    = require './serviceManager'
+
+#-------------------------------------------------------------------------------
+utils.registerClass class MessageHandler
+
+    #---------------------------------------------------------------------------
+    handleMessage: (channel, message) ->
+        @_serviceMethodInvoker(channel, message.interface, message.method, message.args)
+
+    #---------------------------------------------------------------------------
+    _serviceMethodInvoker: (channel, intfName, method, args) ->
+        methodSignature = "#{intfName}.#{method}()"
+        # utils.logVerbose "MessageHandler._serviceMethodInvoker(#{methodSignature})"
+
+        service = serviceManager.get(intfName)
+        
+        if !service
+            return @_redirectToConnections(channel, intfName, method, args)
+
+        args = args.slice()
+        args.unshift channel
+        
+        try 
+            service[method].apply(service, args)
+            
+        catch e
+            utils.log "error running service method #{methodSignature}: #{e}"
+            utils.log "stack:\n#{e.stack}"
+
+    #---------------------------------------------------------------------------
+    _redirectToConnections: (channel, intfName, method, args) ->
+        # utils.logVerbose "MessageHandler._redirectToConnections(#{channel.name}, #{intfName}, #{method})"
+
+        for connection in channel.connections
+            connection.sendMessage(intfName, method, args...)
+            
+#-------------------------------------------------------------------------------
+module.exports = new MessageHandler

http://git-wip-us.apache.org/repos/asf/cordova-weinre/blob/03084bdb/weinre.server/lib-src/service/WeinreClientCommands.coffee
----------------------------------------------------------------------
diff --git a/weinre.server/lib-src/service/WeinreClientCommands.coffee b/weinre.server/lib-src/service/WeinreClientCommands.coffee
new file mode 100644
index 0000000..713a48b
--- /dev/null
+++ b/weinre.server/lib-src/service/WeinreClientCommands.coffee
@@ -0,0 +1,126 @@
+#-------------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#-------------------------------------------------------------------------------
+
+_ = require('underscore')
+
+weinre             = require '../weinre'
+utils              = require '../utils'
+channelManager     = require '../channelManager'
+serviceManager     = require '../serviceManager'
+extensionManager   = require '../extensionManager'
+
+WeinreClientEvents = serviceManager.get 'WeinreClientEvents'
+
+#-------------------------------------------------------------------------------
+module.exports = utils.registerClass class WeinreClientCommands
+
+    #---------------------------------------------------------------------------
+    registerClient: (channel, callbackId) ->
+        if callbackId
+            WeinreClientEvents.sendCallback(channel, callbackId, channel.description)        
+
+        options = _.extend {}, utils.options
+        for own key, val of options
+            if typeof val in ['number', 'boolean']
+                options[key] = "#{val}"
+        
+        options.version = weinre.getVersion()
+        
+        WeinreClientEvents.serverProperties(channel, options)
+
+        clients = channelManager.getClientChannels(channel.id)
+        WeinreClientEvents.clientRegistered(clients, channel.description)
+
+    #---------------------------------------------------------------------------
+    getTargets: (channel, callbackId) ->
+        channels = channelManager.getTargetChannels(channel.id)
+        result = _.pluck(channels, 'description')
+
+        if callbackId
+            WeinreClientEvents.sendCallback(channel, callbackId, [result])
+
+    #---------------------------------------------------------------------------
+    getClients: (channel, callbackId) ->
+        channels = channelManager.getClientChannels(channel.id)
+        result = _.pluck(channels, 'description')
+
+        if callbackId
+            WeinreClientEvents.sendCallback(channel, callbackId, [result])
+
+    #---------------------------------------------------------------------------
+    getExtensions: (channel, callbackId) ->
+        result = for extension in extensionManager.extensions
+            { startPage: "extensions/#{extension}/extension.html" }
+
+        if callbackId
+            WeinreClientEvents.sendCallback(channel, callbackId, [result])
+
+    #---------------------------------------------------------------------------
+    connectTarget: (channel, clientName, targetName, callbackId) ->
+        client = channelManager.getChannel(clientName)
+        return if !client
+
+        target = channelManager.getChannel(targetName)
+        return if !target
+
+        channelManager.connectChannels(client, target)
+
+        if callbackId
+            WeinreClientEvents.sendCallback(channel, callbackId)
+            
+    #---------------------------------------------------------------------------
+    disconnectTarget: (channel, clientName, callbackId) ->
+        client = connectionManager.getClient(clientName)
+        return if !client
+
+        target = client.getConnectedTarget()
+        return if !target
+
+        connectionManager.disconnect(client, target)
+
+        if callbackId
+            WeinreClientEvents.sendCallback(channel, callbackId)
+            
+    #---------------------------------------------------------------------------
+    logDebug: (channel, message, callbackId) ->
+        utils.logVerbose "client #{channel.name}: #{message}"
+
+        if callbackId
+            WeinreClientEvents.sendCallback(channel, callbackId)
+            
+    #---------------------------------------------------------------------------
+    logInfo: (channel, message, callbackId) ->
+        utils.log "client #{channel.name}: #{message}"
+
+        if callbackId
+            WeinreClientEvents.sendCallback(channel, callbackId)
+            
+    #---------------------------------------------------------------------------
+    logWarning: (channel, message, callbackId) ->
+        utils.log "client #{channel.name}: #{message}"
+
+        if callbackId
+            WeinreClientEvents.sendCallback(channel, callbackId)
+            
+    #---------------------------------------------------------------------------
+    logError: (channel, message, callbackId) ->
+        utils.log "client #{channel.name}: #{message}"
+
+        if callbackId
+            WeinreClientEvents.sendCallback(channel, callbackId)

http://git-wip-us.apache.org/repos/asf/cordova-weinre/blob/03084bdb/weinre.server/lib-src/service/WeinreTargetCommands.coffee
----------------------------------------------------------------------
diff --git a/weinre.server/lib-src/service/WeinreTargetCommands.coffee b/weinre.server/lib-src/service/WeinreTargetCommands.coffee
new file mode 100644
index 0000000..4603e20
--- /dev/null
+++ b/weinre.server/lib-src/service/WeinreTargetCommands.coffee
@@ -0,0 +1,90 @@
+#-------------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#-------------------------------------------------------------------------------
+
+utils              = require '../utils'
+channelManager     = require '../channelManager'
+serviceManager     = require '../serviceManager'
+
+WeinreClientEvents = serviceManager.get 'WeinreClientEvents'
+WeinreTargetEvents = serviceManager.get 'WeinreTargetEvents'
+
+#-------------------------------------------------------------------------------
+module.exports = utils.registerClass class WeinreTargetCommands
+
+    #---------------------------------------------------------------------------
+    registerTarget: (channel, url, callbackId) -> 
+        channel.description.url = url
+
+        clients = channelManager.getClientChannels(channel.id)
+        WeinreClientEvents.targetRegistered(clients, channel.description)
+    
+        if callbackId
+            WeinreTargetEvents.sendCallback(channel, callbackId, channel.description)
+
+    #---------------------------------------------------------------------------
+    sendClientCallback: (channel, clientCallbackId, args, callbackId) ->
+
+        # the channel to send the callback to is embedded in the callbackId
+        callbackChannel = getCallbackChannel(clientCallbackId)
+        if !callbackChannel
+            return main.warn "#{@constructor.name}.sendClientCallback() sent with invalid callbackId: #{clientCallbackId}"
+
+        callbackChannel = channelManager.getChannel(callbackChannel)
+        if !callbackChannel
+            # indication that channel was closed; this message may generate a lot of noise
+            return main.warn "#{@constructor.name}.sendClientCallback() unable to find channel : #{clientCallbackId}"
+
+        WeinreClientEvents.sendCallback(callbackChannel, clientCallbackId, args)
+            
+        if callbackId
+            WeinreTargetEvents.sendCallback(channel, callbackId, description)
+
+    #---------------------------------------------------------------------------
+    logDebug: (channel, message, callbackId) ->
+        utils.logVerbose "target #{channel.name}: #{message}"
+
+        if callbackId
+            WeinreTargetEvents.sendCallback(channel, callbackId, description)
+
+    #---------------------------------------------------------------------------
+    logInfo: (channel, message, callbackId) ->
+        utils.log "target #{channel.name}: #{message}"
+
+        if callbackId
+            WeinreTargetEvents.sendCallback(channel, callbackId, description)
+
+    #---------------------------------------------------------------------------
+    logWarning: (channel, message, callbackId) ->
+        utils.log "target #{channel.name}: #{message}"
+
+        if callbackId
+            WeinreTargetEvents.sendCallback(channel, callbackId, description)
+
+    #---------------------------------------------------------------------------
+    logError: (channel, message, callbackId) ->
+        utils.log "target #{channel.name}: #{message}"
+
+        if callbackId
+            WeinreTargetEvents.sendCallback(channel, callbackId, description)
+
+#---------------------------------------------------------------------------
+getCallbackChannel = (callbackId) ->
+    callbackId = callbackId.toString()
+    callbackId.split('::')[0]
+

http://git-wip-us.apache.org/repos/asf/cordova-weinre/blob/03084bdb/weinre.server/lib-src/serviceManager.coffee
----------------------------------------------------------------------
diff --git a/weinre.server/lib-src/serviceManager.coffee b/weinre.server/lib-src/serviceManager.coffee
new file mode 100644
index 0000000..ade070f
--- /dev/null
+++ b/weinre.server/lib-src/serviceManager.coffee
@@ -0,0 +1,95 @@
+#-------------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#-------------------------------------------------------------------------------
+
+path = require 'path'
+fs   = require 'fs'
+
+_ = require 'underscore'
+
+utils = require './utils'
+
+Services = {}
+
+#-------------------------------------------------------------------------------
+utils.registerClass class ServiceManager
+    
+    #---------------------------------------------------------------------------
+    constructor: ->
+        @services = {}
+
+    #---------------------------------------------------------------------------
+    get: (name) ->
+        return @services[name] if _.has(@services, name)
+        
+        null
+
+    #---------------------------------------------------------------------------
+    registerLocalClass: (name) ->
+
+        serviceClass = null
+        try
+            serviceClass = require "./service/#{name}"
+        catch e
+            utils.log "local service class not found: #{name}"
+            throw e
+
+        @services[name] = new serviceClass
+    
+    #---------------------------------------------------------------------------
+    registerProxyClass: (name) ->
+    
+        intf = getServiceInterface(name)
+        
+        if !intf
+            utils.exit "proxy service class not found: #{name}"
+            
+        if intf.name != name
+            utils.exit "proxy interface '#{intf.name}' loaded when '#{name}' requested"
+            
+        service = {}
+        
+        for method in intf.methods
+            service[method.name] = getMethodProxy(name, method.name)    
+            
+        @services[name] = service
+
+
+#-------------------------------------------------------------------------------
+getMethodProxy = (intfName, methodName) ->
+    (channels, args...) ->
+        channels = [channels] if !_.isArray(channels) 
+        
+        for channel in channels
+            channel.sendMessage(intfName, methodName, args...)
+    
+#-------------------------------------------------------------------------------
+getServiceInterface = (name) ->
+    jsonName = "#{name}.json"
+    fileName = path.join utils.options.staticWebDir, 'interfaces', jsonName
+    
+    return null if !utils.fileExistsSync(fileName) 
+    
+    contents = fs.readFileSync(fileName, 'utf8')
+    
+    serviceInterface = JSON.parse(contents)
+    
+    return serviceInterface.interfaces[0]
+
+#-------------------------------------------------------------------------------
+module.exports = new ServiceManager
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-weinre/blob/03084bdb/weinre.server/lib-src/utils.coffee
----------------------------------------------------------------------
diff --git a/weinre.server/lib-src/utils.coffee b/weinre.server/lib-src/utils.coffee
new file mode 100644
index 0000000..ee5a72b
--- /dev/null
+++ b/weinre.server/lib-src/utils.coffee
@@ -0,0 +1,196 @@
+#-------------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#-------------------------------------------------------------------------------
+
+fs   = require 'fs'
+path = require 'path'
+
+utils = exports
+
+utils.Program = Program = path.basename process.argv[1]
+
+SequenceNumberMax = 100 * 1024 * 1024
+SequenceNumber    = 0
+
+#-------------------------------------------------------------------------------
+utils.getNextSequenceNumber = (g) -> 
+    SequenceNumber++
+    
+    if SequenceNumber > SequenceNumberMax
+        SequenceNumber = 0
+        
+    SequenceNumber
+
+#-------------------------------------------------------------------------------
+utils.trim = (string) -> 
+    string.replace(/(^\s+)|(\s+$)/g,'')
+
+#-------------------------------------------------------------------------------
+utils.log = log = (message) ->
+    date    = new Date()
+    time    = date.toISOString()
+    console.log "#{time} #{Program}: #{message}"
+
+#-------------------------------------------------------------------------------
+utils.logVerbose = (message) ->
+    return if !utils?.options?.verbose
+
+    log message
+
+#-------------------------------------------------------------------------------
+utils.logDebug = (message) ->
+    return if !utils?.options?.debug
+
+    log message
+
+#-------------------------------------------------------------------------------
+utils.exit = (message) ->
+    log message
+    process.exit 1
+
+#-------------------------------------------------------------------------------
+utils.pitch = (message) ->
+    log message
+    throw message
+
+#-------------------------------------------------------------------------------
+utils.setOptions = (options) ->
+    utils.options = options
+    
+#-------------------------------------------------------------------------------
+utils.ensureInteger = (value, message) ->
+    newValue = parseInt value
+    
+    if isNaN newValue
+        utils.exit "#{message}: '#{value}'"
+    
+    newValue    
+    
+#-------------------------------------------------------------------------------
+utils.ensureString = (value, message) ->
+    
+    if typeof value != 'string'
+        utils.exit "#{message}: '#{value}'"
+    
+    value    
+    
+#-------------------------------------------------------------------------------
+utils.ensureBoolean = (value, message) ->
+    uValue = value.toString().toUpperCase()
+
+    newValue = null    
+    switch uValue
+        when 'TRUE'  then newValue = true
+        when 'FALSE' then newValue = false
+    
+    if typeof(newValue) != 'boolean'
+        utils.exit "#{message}: '#{value}'"
+    
+    newValue
+
+#-------------------------------------------------------------------------------
+utils.setNamesForClass = (aClass) ->
+
+    for own key, val of aClass
+        if typeof(val) is "function"
+            val.signature   = "#{aClass.name}::#{key}"
+            val.displayName = val.signature
+            val.name        = val.signature
+
+    for own key, val of aClass.prototype
+        if typeof(val) is "function"
+            val.signature   = "#{aClass.name}.#{key}"
+            val.displayName = val.signature
+            val.name        = val.signature
+
+#-------------------------------------------------------------------------------
+utils.registerClass = (aClass) ->
+    utils.setNamesForClass(aClass)
+    aClass
+
+#-------------------------------------------------------------------------------
+utils.alignLeft = (string, length) ->
+    while string.length < length
+        string = "#{string} "
+        
+    string
+
+#-------------------------------------------------------------------------------
+utils.alignRight = (string, length) ->
+    while string.length < length
+        string = " #{string}"
+
+    string
+
+#-------------------------------------------------------------------------------
+utils.fileExistsSync = (name) ->
+    
+    if fs.existsSync
+        return fs.existsSync name
+        
+    return path.existsSync(name)
+
+#-------------------------------------------------------------------------------
+Error.prepareStackTrace = (error, structuredStackTrace) ->
+    result = []
+    result.push "---------------------------------------------------------"
+    result.push "error: #{error}"
+    result.push "---------------------------------------------------------"
+    result.push "stack: "
+
+    longestFile = 0
+    longestLine = 0
+    
+    for callSite in structuredStackTrace
+        file = callSite.getFileName()
+        line = callSite.getLineNumber()
+
+        file = path.basename(file)
+        line = "#{line}"
+        
+        if file.length > longestFile
+            longestFile = file.length
+    
+        if line.length > longestLine
+            longestLine = line.length
+    
+    for callSite in structuredStackTrace
+        func = callSite.getFunction()
+        file = callSite.getFileName()
+        line = callSite.getLineNumber()
+
+        file = path.basename(file)
+        line = "#{line}"
+        
+        file = utils.alignRight(file, longestFile)
+        line = utils.alignLeft( line, longestLine)
+        
+        funcName = func.displayName ||
+                   func.name || 
+                   callSite.getFunctionName()
+                   callSite.getMethodName()
+                   '???'
+        
+        if funcName == "Module._compile"
+            result.pop()
+            result.pop()
+            break
+            
+        result.push "   #{file}:#{line} - #{funcName}()"
+        
+    result.join "\n"

http://git-wip-us.apache.org/repos/asf/cordova-weinre/blob/03084bdb/weinre.server/lib-src/weinre.coffee
----------------------------------------------------------------------
diff --git a/weinre.server/lib-src/weinre.coffee b/weinre.server/lib-src/weinre.coffee
new file mode 100644
index 0000000..8b7945d
--- /dev/null
+++ b/weinre.server/lib-src/weinre.coffee
@@ -0,0 +1,186 @@
+#-------------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#-------------------------------------------------------------------------------
+
+fs   = require 'fs'
+net  = require 'net'
+dns  = require 'dns'
+path = require 'path'
+
+_       = require 'underscore'
+express = require 'express'
+
+utils              = require './utils'
+jsonBodyParser     = require './jsonBodyParser'
+HttpChannelHandler = require './HttpChannelHandler'
+dumpingHandler     = require './dumpingHandler'
+channelManager     = require './channelManager'
+serviceManager     = require './serviceManager'
+
+#-------------------------------------------------------------------------------
+exports.run = (options) ->
+    processOptions(options, run2)
+
+#-------------------------------------------------------------------------------
+run2 = ->
+    options = utils.options
+    
+    serviceManager.registerProxyClass 'WeinreClientEvents'
+    serviceManager.registerProxyClass 'WeinreTargetEvents'
+    serviceManager.registerLocalClass 'WeinreClientCommands'
+    serviceManager.registerLocalClass 'WeinreTargetCommands'
+    
+    startDeathWatcher options.deathTimeout
+    
+    startServer()    
+
+#-------------------------------------------------------------------------------
+processOptions = (options, cb) ->
+    options.httpPort     = utils.ensureInteger( options.httpPort,     'the value of the option httpPort is not a number')
+    options.boundHost    = utils.ensureString(  options.boundHost,    'the value of the option boundHost is not a string')
+    options.verbose      = utils.ensureBoolean( options.verbose,      'the value of the option verbose is not a boolean')
+    options.debug        = utils.ensureBoolean( options.debug,        'the value of the option debug is not a boolean')
+    options.readTimeout  = utils.ensureInteger( options.readTimeout,  'the value of the option readTimeout is not a number')
+    options.deathTimeout = utils.ensureInteger( options.deathTimeout, 'the value of the option deathTimeout is not a number')
+
+    options.verbose = true if options.debug
+    
+    options.staticWebDir = getStaticWebDir()
+    
+    utils.logVerbose "pid:                 #{process.pid}"
+    utils.logVerbose "version:             #{getVersion()}"
+    utils.logVerbose "node versions:"
+    
+    names   = _.keys(process.versions)
+    reducer = (memo, name) -> Math.max(memo, name.length)
+    nameLen = _.reduce(names, reducer, 0)
+    
+    for name in names
+        utils.logVerbose "   #{utils.alignLeft(name, nameLen)}: #{process.versions[name]}"
+    
+    utils.logVerbose "options:"
+    utils.logVerbose "   httpPort:     #{options.httpPort}"
+    utils.logVerbose "   boundHost:    #{options.boundHost}"
+    utils.logVerbose "   verbose:      #{options.verbose}"
+    utils.logVerbose "   debug:        #{options.debug}"
+    utils.logVerbose "   readTimeout:  #{options.readTimeout}"
+    utils.logVerbose "   deathTimeout: #{options.deathTimeout}"
+
+    utils.setOptions options
+
+    checkHost options.boundHost, (err) ->
+        if err
+            utils.exit "unable to resolve boundHost address: #{options.boundHost}"
+
+        cb()
+
+#-------------------------------------------------------------------------------
+checkHost = (hostName, cb) ->
+    return cb() if hostName == '-all-'
+    return cb() if hostName == 'localhost'
+    
+    return cb() if net.isIP(hostName)
+    
+    dns.lookup hostName, cb
+
+#-------------------------------------------------------------------------------
+deathTimeout = null
+
+#-------------------------------------------------------------------------------
+startDeathWatcher = (timeout) ->
+    deathTimeout = utils.options.deathTimeout * 1000
+    
+    setInterval checkForDeath, 1000
+
+#-------------------------------------------------------------------------------
+checkForDeath = ->
+    now = (new Date).valueOf()
+    for channel in channelManager.getChannels()
+        if now - channel.lastRead > deathTimeout
+            channel.close()
+
+#-------------------------------------------------------------------------------
+startServer = () ->
+    options = utils.options
+
+    clientHandler = new HttpChannelHandler('/ws/client')
+    targetHandler = new HttpChannelHandler('/ws/target')
+    
+    channelManager.initialize()
+    
+    favIcon = "#{options.staticWebDir}/images/weinre-icon-32x32.png"
+
+    staticCacheOptions =
+        maxObjects: 500
+        maxLength:  32 * 1024 * 1024
+        
+    app = express.createServer()
+    
+    app.on 'error', (error) ->
+        utils.exit "error running server: #{error}"
+
+    app.use express.favicon(favIcon)
+
+    app.use jsonBodyParser()
+
+    app.all /^\/ws\/client(.*)/, (request, response, next) ->
+        uri = request.params[0]
+        uri = '/' if uri == ''
+        
+        dumpingHandler(request, response, uri) if options.debug
+        clientHandler.handle(request, response, uri)
+
+    app.all /^\/ws\/target(.*)/, (request, response, next) ->
+        uri = request.params[0]
+        uri = '/' if uri == ''
+
+        dumpingHandler(request, response, uri) if options.debug
+        targetHandler.handle(request, response, uri)
+
+    app.use express.errorHandler(dumpExceptions: true)
+
+    app.use express.staticCache(staticCacheOptions)
+    app.use express.static(options.staticWebDir)
+    
+    if options.boundHost == '-all-'
+        utils.log "starting server at http://localhost:#{options.httpPort}"
+        app.listen options.httpPort
+        
+    else
+        utils.log "starting server at http://#{options.boundHost}:#{options.httpPort}"
+        app.listen options.httpPort, options.boundHost
+
+#-------------------------------------------------------------------------------
+getStaticWebDir = () ->
+    webDir = path.normalize path.join(__dirname,'../web')
+    return webDir if utils.fileExistsSync webDir
+    
+    utils.exit 'unable to find static files to serve in #{webDir}; did you do a build?'
+    
+#-------------------------------------------------------------------------------
+Version = null
+getVersion = exports.getVersion = () ->
+    return Version if Version 
+
+    packageJsonName  = path.join(path.dirname(fs.realpathSync(__filename)), '../package.json')
+
+    json = fs.readFileSync(packageJsonName, 'utf8')
+    values = JSON.parse(json)
+
+    Version = values.version
+    return Version

http://git-wip-us.apache.org/repos/asf/cordova-weinre/blob/03084bdb/weinre.server/lib/Channel.coffee
----------------------------------------------------------------------
diff --git a/weinre.server/lib/Channel.coffee b/weinre.server/lib/Channel.coffee
deleted file mode 100644
index 70f5841..0000000
--- a/weinre.server/lib/Channel.coffee
+++ /dev/null
@@ -1,118 +0,0 @@
-#-------------------------------------------------------------------------------
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#-------------------------------------------------------------------------------
-
-_ = require 'underscore'
-
-utils          = require './utils'
-channelManager = require './channelManager'
-messageHandler = require './messageHandler'
-MessageQueue   = require './MessageQueue'
-
-AnonymousId = 'anonymous'
-
-#-------------------------------------------------------------------------------
-module.exports = utils.registerClass class Channel
-    
-    #---------------------------------------------------------------------------
-    constructor: (@pathPrefix, @id, @remoteAddress, @isClient) ->
-        prefix         = if @isClient then 'c-' else 't-'
-        @name          = "#{prefix}#{utils.getNextSequenceNumber()}"
-        @messageQueue  = new MessageQueue
-        @isClosed      = false
-        @connections   = []
-        @isTarget      = !@isClient
-        @readTimeout   = utils.options.readTimeout * 1000
-        
-        @id = AnonymousId if !@id 
-        
-        @description = 
-            channel:       @name
-            id:            @id
-            hostName:      @remoteAddress
-            remoteAddress: @remoteAddress
-        
-        @updateLastRead()
-
-        channelManager.created @
-
-    #---------------------------------------------------------------------------
-    close: () ->
-        return if @isClosed
-        
-        channelManager.destroyed @
-        
-        @isClosed = true
-        @messageQueue.shutdown()
-
-    #---------------------------------------------------------------------------
-    sendCallback: (intfName, callbackId, args...) ->
-        return if !callbackId
-        
-        args.unshift callbackId
-        
-        @sendMessage intfName, 'sendCallback', args...
-        
-    #---------------------------------------------------------------------------
-    sendMessage: (intfName, method, args...) ->
-
-        message = genJSON
-            interface: intfName
-            method:    method
-            args:      args
-        
-        @messageQueue.push message
-
-    #---------------------------------------------------------------------------
-    handleMessages: (messages) ->
-
-        for message in messages
-            message = parseJSON(message)
-            continue if !message
-            
-            messageHandler.handleMessage @, message
-        
-    #---------------------------------------------------------------------------
-    getMessages: (callback) ->
-        @updateLastRead()
-        return callback.call(null, null) if @isClosed
-        
-        @messageQueue.pullAll @readTimeout, callback
-        
-    #---------------------------------------------------------------------------
-    updateLastRead: () ->
-        @lastRead = (new Date).valueOf()
-
-    #---------------------------------------------------------------------------
-    toString: () ->
-        connections = _.map(@connections, (val) -> val.name).join(',')
-        "Channel(#{@name}, closed:#{@isClosed}, connections:[#{connections}])"
-
-#-------------------------------------------------------------------------------
-parseJSON = (message) ->
-    try 
-        return JSON.parse(message)
-    catch e
-        return null
-
-#-------------------------------------------------------------------------------
-genJSON = (message) ->
-    try 
-        return JSON.stringify(message)
-    catch e
-        return null

http://git-wip-us.apache.org/repos/asf/cordova-weinre/blob/03084bdb/weinre.server/lib/Channel.js
----------------------------------------------------------------------
diff --git a/weinre.server/lib/Channel.js b/weinre.server/lib/Channel.js
new file mode 100644
index 0000000..040e4c3
--- /dev/null
+++ b/weinre.server/lib/Channel.js
@@ -0,0 +1,130 @@
+// Generated by CoffeeScript 1.8.0
+var AnonymousId, Channel, MessageQueue, channelManager, genJSON, messageHandler, parseJSON, utils, _,
+  __slice = [].slice;
+
+_ = require('underscore');
+
+utils = require('./utils');
+
+channelManager = require('./channelManager');
+
+messageHandler = require('./messageHandler');
+
+MessageQueue = require('./MessageQueue');
+
+AnonymousId = 'anonymous';
+
+module.exports = utils.registerClass(Channel = (function() {
+  function Channel(pathPrefix, id, remoteAddress, isClient) {
+    var prefix;
+    this.pathPrefix = pathPrefix;
+    this.id = id;
+    this.remoteAddress = remoteAddress;
+    this.isClient = isClient;
+    prefix = this.isClient ? 'c-' : 't-';
+    this.name = "" + prefix + (utils.getNextSequenceNumber());
+    this.messageQueue = new MessageQueue;
+    this.isClosed = false;
+    this.connections = [];
+    this.isTarget = !this.isClient;
+    this.readTimeout = utils.options.readTimeout * 1000;
+    if (!this.id) {
+      this.id = AnonymousId;
+    }
+    this.description = {
+      channel: this.name,
+      id: this.id,
+      hostName: this.remoteAddress,
+      remoteAddress: this.remoteAddress
+    };
+    this.updateLastRead();
+    channelManager.created(this);
+  }
+
+  Channel.prototype.close = function() {
+    if (this.isClosed) {
+      return;
+    }
+    channelManager.destroyed(this);
+    this.isClosed = true;
+    return this.messageQueue.shutdown();
+  };
+
+  Channel.prototype.sendCallback = function() {
+    var args, callbackId, intfName;
+    intfName = arguments[0], callbackId = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
+    if (!callbackId) {
+      return;
+    }
+    args.unshift(callbackId);
+    return this.sendMessage.apply(this, [intfName, 'sendCallback'].concat(__slice.call(args)));
+  };
+
+  Channel.prototype.sendMessage = function() {
+    var args, intfName, message, method;
+    intfName = arguments[0], method = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
+    message = genJSON({
+      "interface": intfName,
+      method: method,
+      args: args
+    });
+    return this.messageQueue.push(message);
+  };
+
+  Channel.prototype.handleMessages = function(messages) {
+    var message, _i, _len, _results;
+    _results = [];
+    for (_i = 0, _len = messages.length; _i < _len; _i++) {
+      message = messages[_i];
+      message = parseJSON(message);
+      if (!message) {
+        continue;
+      }
+      _results.push(messageHandler.handleMessage(this, message));
+    }
+    return _results;
+  };
+
+  Channel.prototype.getMessages = function(callback) {
+    this.updateLastRead();
+    if (this.isClosed) {
+      return callback.call(null, null);
+    }
+    return this.messageQueue.pullAll(this.readTimeout, callback);
+  };
+
+  Channel.prototype.updateLastRead = function() {
+    return this.lastRead = (new Date).valueOf();
+  };
+
+  Channel.prototype.toString = function() {
+    var connections;
+    connections = _.map(this.connections, function(val) {
+      return val.name;
+    }).join(',');
+    return "Channel(" + this.name + ", closed:" + this.isClosed + ", connections:[" + connections + "])";
+  };
+
+  return Channel;
+
+})());
+
+parseJSON = function(message) {
+  var e;
+  try {
+    return JSON.parse(message);
+  } catch (_error) {
+    e = _error;
+    return null;
+  }
+};
+
+genJSON = function(message) {
+  var e;
+  try {
+    return JSON.stringify(message);
+  } catch (_error) {
+    e = _error;
+    return null;
+  }
+};