merge from trunk to javascript branch
diff --git a/examples/messenger/c/CMakeLists.txt b/examples/messenger/c/CMakeLists.txt
index 4f40924..1b32d0c 100644
--- a/examples/messenger/c/CMakeLists.txt
+++ b/examples/messenger/c/CMakeLists.txt
@@ -21,8 +21,12 @@
 
 add_executable(recv recv.c)
 add_executable(send send.c)
+add_executable(recv-async recv-async.c)
+add_executable(send-async send-async.c)
 
 include_directories(${Proton_INCLUDE_DIRS})
 
 target_link_libraries(recv ${Proton_LIBRARIES})
 target_link_libraries(send ${Proton_LIBRARIES})
+target_link_libraries(recv-async ${Proton_LIBRARIES})
+target_link_libraries(send-async ${Proton_LIBRARIES})
diff --git a/examples/messenger/c/recv-async.c b/examples/messenger/c/recv-async.c
new file mode 100644
index 0000000..1f49166
--- /dev/null
+++ b/examples/messenger/c/recv-async.c
@@ -0,0 +1,193 @@
+/*
+ * 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.
+ *
+ */
+
+// This is a re-implementation of recv.c using non-blocking/asynchronous calls.
+
+#include "proton/message.h"
+#include "proton/messenger.h"
+
+#include "pncompat/misc_funcs.inc"
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#if EMSCRIPTEN
+#include <emscripten.h>
+#endif
+
+pn_message_t * message;
+pn_messenger_t * messenger;
+
+#define check(messenger)                                                     \
+  {                                                                          \
+    if(pn_messenger_errno(messenger))                                        \
+    {                                                                        \
+      die(__FILE__, __LINE__, pn_error_text(pn_messenger_error(messenger))); \
+    }                                                                        \
+  }                                                                          \
+
+void die(const char *file, int line, const char *message)
+{
+    fprintf(stderr, "%s:%i: %s\n", file, line, message);
+    exit(1);
+}
+
+void usage(void)
+{
+    printf("Usage: recv [options] <addr>\n");
+    printf("-c    \tPath to the certificate file.\n");
+    printf("-k    \tPath to the private key file.\n");
+    printf("-p    \tPassword for the private key.\n");
+    printf("<addr>\tAn address.\n");
+    exit(0);
+}
+
+void process(void) {
+    while(pn_messenger_incoming(messenger))
+    {
+        pn_messenger_get(messenger, message);
+        check(messenger);
+
+        {
+        pn_tracker_t tracker = pn_messenger_incoming_tracker(messenger);
+        char buffer[1024];
+        size_t buffsize = sizeof(buffer);
+        const char* subject = pn_message_get_subject(message);
+        pn_data_t* body = pn_message_body(message);
+        pn_data_format(body, buffer, &buffsize);
+
+        printf("Address: %s\n", pn_message_get_address(message));
+        printf("Subject: %s\n", subject ? subject : "(no subject)");
+        printf("Content: %s\n", buffer);
+
+        pn_messenger_accept(messenger, tracker, 0);
+        }
+    }
+}
+
+#if EMSCRIPTEN // For emscripten C/C++ to JavaScript compiler.
+void pump(int fd, void* userData) {
+    while (pn_messenger_work(messenger, 0) >= 0) {
+        process();
+    }
+}
+
+void onclose(int fd, void* userData) {
+    process();
+}
+
+void onerror(int fd, int errno, const char* msg, void* userData) {
+    printf("error callback fd = %d, errno = %d, msg = %s\n", fd, errno, msg);
+}
+#endif
+
+int main(int argc, char** argv)
+{
+    char* certificate = NULL;
+    char* privatekey = NULL;
+    char* password = NULL;
+    char* address = (char *) "amqp://~0.0.0.0";
+    int c;
+
+    message = pn_message();
+    messenger = pn_messenger(NULL);
+    pn_messenger_set_blocking(messenger, false); // Needs to be set non-blocking to behave asynchronously.
+
+    opterr = 0;
+
+    while((c = getopt(argc, argv, "hc:k:p:")) != -1)
+    {
+        switch(c)
+        {
+            case 'h':
+                usage();
+                break;
+
+            case 'c': certificate = optarg; break;
+            case 'k': privatekey = optarg; break;
+            case 'p': password = optarg; break;
+
+            case '?':
+                if (optopt == 'c' ||
+                    optopt == 'k' ||
+                    optopt == 'p')
+                {
+                    fprintf(stderr, "Option -%c requires an argument.\n", optopt);
+                }
+                else if(isprint(optopt))
+                {
+                    fprintf(stderr, "Unknown option `-%c'.\n", optopt);
+                }
+                else
+                {
+                    fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
+                }
+                return 1;
+            default:
+                abort();
+        }
+    }
+
+    if (optind < argc)
+    {
+        address = argv[optind];
+    }
+
+    /* load the various command line options if they're set */
+    if(certificate)
+    {
+        pn_messenger_set_certificate(messenger, certificate);
+    }
+
+    if(privatekey)
+    {
+        pn_messenger_set_private_key(messenger, privatekey);
+    }
+
+    if(password)
+    {
+        pn_messenger_set_password(messenger, password);
+    }
+
+    pn_messenger_start(messenger);
+    check(messenger);
+
+    pn_messenger_subscribe(messenger, address);
+    check(messenger);
+
+    pn_messenger_recv(messenger, -1); // Set to receive as many messages as messenger can buffer.
+
+#if EMSCRIPTEN // For emscripten C/C++ to JavaScript compiler.
+    emscripten_set_socket_error_callback(NULL, onerror);
+
+    emscripten_set_socket_open_callback(NULL, pump);
+    emscripten_set_socket_connection_callback(NULL, pump);
+    emscripten_set_socket_message_callback(NULL, pump);
+    emscripten_set_socket_close_callback(NULL, onclose);
+#else // For native compiler.
+    while (1) {
+        pn_messenger_work(messenger, -1); // Block indefinitely until there has been socket activity.
+        process();
+    }
+#endif
+
+    return 0;
+}
+
diff --git a/examples/messenger/c/send-async.c b/examples/messenger/c/send-async.c
new file mode 100644
index 0000000..2c76e6c
--- /dev/null
+++ b/examples/messenger/c/send-async.c
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ *
+ */
+
+// This is a re-implementation of send.c using non-blocking/asynchronous calls.
+
+#include "proton/message.h"
+#include "proton/messenger.h"
+#include "proton/driver.h"
+
+#include "pncompat/misc_funcs.inc"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#if EMSCRIPTEN
+#include <emscripten.h>
+#endif
+
+pn_message_t * message;
+pn_messenger_t * messenger;
+pn_tracker_t tracker;
+int running = 1;
+
+#define check(messenger)                                                     \
+  {                                                                          \
+    if(pn_messenger_errno(messenger))                                        \
+    {                                                                        \
+      die(__FILE__, __LINE__, pn_error_text(pn_messenger_error(messenger))); \
+    }                                                                        \
+  }                                                                          \
+
+void die(const char *file, int line, const char *message)
+{
+    fprintf(stderr, "%s:%i: %s\n", file, line, message);
+    exit(1);
+}
+
+void usage(void)
+{
+    printf("Usage: send [-a addr] [message]\n");
+    printf("-a     \tThe target address [amqp[s]://domain[/name]]\n");
+    printf("message\tA text string to send.\n");
+    exit(0);
+}
+
+void process(void) {
+    pn_status_t status = pn_messenger_status(messenger, tracker);
+    if (status != PN_STATUS_PENDING) {
+        if (running) {
+            pn_messenger_stop(messenger);
+            running = 0;
+        } 
+    }
+
+    if (pn_messenger_stopped(messenger)) {
+        pn_message_free(message);
+        pn_messenger_free(messenger);
+    }
+}
+
+#if EMSCRIPTEN // For emscripten C/C++ to JavaScript compiler.
+void pump(int fd, void* userData) {
+    while (pn_messenger_work(messenger, 0) >= 0) {
+        process();
+    }
+}
+
+void onclose(int fd, void* userData) {
+    process();
+}
+
+void onerror(int fd, int errno, const char* msg, void* userData) {
+    printf("error callback fd = %d, errno = %d, msg = %s\n", fd, errno, msg);
+}
+#endif
+
+int main(int argc, char** argv)
+{
+    int c;
+    opterr = 0;
+    char * address = (char *) "amqp://0.0.0.0";
+    char * msgtext = (char *) "Hello World!";
+
+    while((c = getopt(argc, argv, "ha:b:c:")) != -1)
+    {
+        switch(c)
+        {
+            case 'a': address = optarg; break;
+            case 'h': usage(); break;
+
+            case '?':
+                if(optopt == 'a')
+                {
+                    fprintf(stderr, "Option -%c requires an argument.\n", optopt);
+                }
+                else if(isprint(optopt))
+                {
+                    fprintf(stderr, "Unknown option `-%c'.\n", optopt);
+                }
+                else
+                {
+                    fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
+                }
+                return 1;
+            default:
+                abort();
+        }
+    }
+
+    if (optind < argc) msgtext = argv[optind];
+
+    message = pn_message();
+    messenger = pn_messenger(NULL);
+    pn_messenger_set_blocking(messenger, false); // Needs to be set non-blocking to behave asynchronously.
+    pn_messenger_set_outgoing_window(messenger, 1024); 
+
+    pn_messenger_start(messenger);
+
+    pn_message_set_address(message, address);
+    pn_data_t* body = pn_message_body(message);
+    pn_data_put_string(body, pn_bytes(strlen(msgtext), msgtext));
+
+    pn_messenger_put(messenger, message);
+    check(messenger);
+
+    tracker = pn_messenger_outgoing_tracker(messenger);
+
+#if EMSCRIPTEN // For emscripten C/C++ to JavaScript compiler.
+    emscripten_set_socket_error_callback(NULL, onerror);
+
+    emscripten_set_socket_open_callback(NULL, pump);
+    emscripten_set_socket_connection_callback(NULL, pump);
+    emscripten_set_socket_message_callback(NULL, pump);
+    emscripten_set_socket_close_callback(NULL, onclose);
+#else // For native compiler.
+    while (running) {
+        pn_messenger_work(messenger, -1); // Block indefinitely until there has been socket activity.
+        process();
+    }
+
+    while (!pn_messenger_stopped(messenger)) {
+        pn_messenger_work(messenger, 0);
+        process();
+    }
+#endif
+
+    return 0;
+}
+
diff --git a/examples/messenger/javascript/client.js b/examples/messenger/javascript/client.js
new file mode 100644
index 0000000..62f9a61
--- /dev/null
+++ b/examples/messenger/javascript/client.js
@@ -0,0 +1,104 @@
+#!/usr/bin/env node
+/*
+ * 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.
+ *
+ */
+
+// Simple client for use with server.js illustrating request/response
+
+// Check if the environment is Node.js and if not log an error and exit.
+if (typeof process === 'object' && typeof require === 'function') {
+    var proton = require("qpid-proton");
+
+    var address = "amqp://0.0.0.0";
+    var subject = "UK.WEATHER";
+    var replyTo = "~/replies";
+    var msgtext = "Hello World!";
+    var tracker = null;
+    var running = true;
+
+    var message = new proton.Message();
+    var messenger = new proton.Messenger();
+
+    var pumpData = function() {
+        while (messenger.incoming()) {
+            var t = messenger.get(message);
+
+            console.log("Reply");
+            console.log("Address: " + message.getAddress());
+            console.log("Subject: " + message.getSubject());
+
+            // body is the body as a native JavaScript Object, useful for most real cases.
+            //console.log("Content: " + message.body);
+
+            // data is the body as a proton.Data Object, used in this case because
+            // format() returns exactly the same representation as recv.c
+            console.log("Content: " + message.data.format());
+
+            messenger.accept(t);
+            messenger.stop();
+        }
+
+        if (messenger.isStopped()) {
+            message.free();
+            messenger.free();
+        }
+    };
+
+    var args = process.argv.slice(2);
+    if (args.length > 0) {
+        if (args[0] === '-h' || args[0] === '--help') {
+            console.log("Usage: node client.js [-r replyTo] [-s subject] <addr> (default " + address + ")");
+            console.log("Options:");
+            console.log("  -r <reply to> The message replyTo (default " + replyTo + ")");
+            console.log("  -s <subject> The message subject (default " + subject + ")");
+            process.exit(0);
+        }
+
+        for (var i = 0; i < args.length; i++) {
+            var arg = args[i];
+            if (arg.charAt(0) === '-') {
+                i++;
+                var val = args[i];
+                if (arg === '-r') {
+                    replyTo = val;
+                } else if (arg === '-s') {
+                    subject = val;
+                }
+            } else {
+                address = arg;
+            }
+        }
+    }
+
+    messenger.on('error', function(error) {console.log(error);});
+    messenger.on('work', pumpData);
+    messenger.setOutgoingWindow(1024);
+    messenger.recv(); // Receive as many messages as messenger can buffer.
+    messenger.start();
+
+    message.setAddress(address);
+    message.setSubject(subject);
+    message.setReplyTo(replyTo);
+    message.body = msgtext;
+
+    tracker = messenger.put(message);
+} else {
+    console.error("client.js should be run in Node.js");
+}
+
diff --git a/examples/messenger/javascript/drain.js b/examples/messenger/javascript/drain.js
new file mode 100644
index 0000000..04ced73
--- /dev/null
+++ b/examples/messenger/javascript/drain.js
@@ -0,0 +1,70 @@
+#!/usr/bin/env node
+/*
+ * 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.
+ *
+ */
+
+// Check if the environment is Node.js and if not log an error and exit.
+if (typeof process === 'object' && typeof require === 'function') {
+    var proton = require("qpid-proton");
+
+    console.log("drain not implemented yet");
+    process.exit(0);
+
+    var address = "amqp://~0.0.0.0";
+    var message = new proton.Message();
+    var messenger = new proton.Messenger();
+
+    var pumpData = function() {
+        while (messenger.incoming()) {
+            var t = messenger.get(message);
+
+            console.log("Address: " + message.getAddress());
+            console.log("Subject: " + message.getSubject());
+    
+            // body is the body as a native JavaScript Object, useful for most real cases.
+            //console.log("Content: " + message.body);
+
+            // data is the body as a proton.Data Object, used in this case because
+            // format() returns exactly the same representation as recv.c
+            console.log("Content: " + message.data.format());
+
+            messenger.accept(t);
+        }
+    };
+
+    var args = process.argv.slice(2);
+    if (args.length > 0) {
+        if (args[0] === '-h' || args[0] === '--help') {
+            console.log("Usage: recv <addr> (default " + address + ").");
+            process.exit(0);
+        }
+
+        address = args[0];
+    }
+
+    messenger.on('error', function(error) {console.log(error);});
+    messenger.on('work', pumpData);
+    messenger.recv(); // Receive as many messages as messenger can buffer.
+    messenger.start();
+
+    messenger.subscribe(address);
+} else {
+    console.error("drain.js should be run in Node.js");
+}
+
diff --git a/examples/messenger/javascript/proxy.js b/examples/messenger/javascript/proxy.js
new file mode 100755
index 0000000..cac5cf5
--- /dev/null
+++ b/examples/messenger/javascript/proxy.js
@@ -0,0 +1,105 @@
+#!/usr/bin/env node
+/*
+ * 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.
+ *
+ */
+
+/**
+ * proxy.js is a simple node.js command line application that uses the ws2tcp.js
+ * library to proxy from a WebSocket to a TCP Socket or vice versa.
+ * <p>
+ * Usage: node proxy.js [options]
+ * Options:");
+ *  -p <listen port>, --port  <listen port> (default 5673 for ws2tcp
+ *                                                   5672 for tcp2ws)
+ *  -t <target port>, --tport <target port> (default listen port - 1 for ws2tcp
+ *                                                   listen port + 1 for tcp2ws)
+ *  -h <target host>, --thost <target host> (default 0.0.0.0)
+ *  -m <ws2tcp or tcp2ws>, --method <ws2tcp or tcp2ws> (default ws2tcp)
+ * @Author Fraser Adams
+ * @file
+ */
+
+// Check if the environment is Node.js and if not log an error and exit.
+if (typeof process === 'object' && typeof require === 'function') {
+    var proxy = require('./ws2tcp.js');
+
+    var lport = 5673;
+    var tport = lport - 1;
+    var thost = '0.0.0.0';
+    var method = 'ws2tcp';
+
+    var args = process.argv.slice(2);
+    if (args.length > 0) {
+        if (args[0] === '-h' || args[0] === '--help') {
+            console.log("Usage: node proxy.js [options]");
+            console.log("Options:");
+            console.log("  -p <listen port>, --port  <listen port> (default " + lport + " for ws2tcp");
+            console.log("                                                   " + tport + " for tcp2ws)");
+            console.log("  -t <target port>, --tport <target port> (default listen port - 1 for ws2tcp");
+            console.log("                                                   listen port + 1 for tcp2ws)");
+            console.log("  -h <target host>, --thost <target host> (default " + thost + ")");
+            console.log("  -m <ws2tcp or tcp2ws>, --method <ws2tcp or tcp2ws> (default " + method + ")");
+            process.exit(0);
+        }
+
+        var lportSet = false;
+        var tportSet = false;
+        for (var i = 0; i < args.length; i++) {
+            var arg = args[i];
+            if (arg.charAt(0) === '-') {
+                i++;
+                var val = args[i];
+                if (arg === '-p' || arg === '--port') {
+                    lport = val;
+                    lportSet = true;
+                } else if (arg === '-t' || arg === '--tport') {
+                    tport = val;
+                    tportSet = true;
+                } else if (arg === '-h' || arg === '--thost') {
+                    thost = val;
+                } else if (arg === '-m' || arg === '--method') {
+                    method = val;
+                }
+            }
+        }
+
+        if (method === 'tcp2ws' && !lportSet) {
+            lport--;
+        }
+
+        if (!tportSet) {
+            tport = (method === 'ws2tcp') ? lport - 1 : +lport + 1;
+        }
+    }
+
+    if (method === 'tcp2ws') {
+        console.log("Proxying tcp -> ws");
+        console.log("Forwarding port " + lport + " to " + thost + ":" + tport);
+        proxy.tcp2ws(lport, thost, tport, 'AMQPWSB10');
+    } else if (method === 'ws2tcp') {
+        console.log("Proxying ws -> tcp");
+        console.log("Forwarding port " + lport + " to " + thost + ":" + tport);
+        proxy.ws2tcp(lport, thost, tport);
+    } else {
+        console.error("Method must be either ws2tcp or tcp2ws.");
+    }
+} else {
+    console.error("proxy.js should be run in Node.js");
+}
+
diff --git a/examples/messenger/javascript/qpid-config.js b/examples/messenger/javascript/qpid-config.js
new file mode 100755
index 0000000..2f2a2ee
--- /dev/null
+++ b/examples/messenger/javascript/qpid-config.js
@@ -0,0 +1,1511 @@
+#!/usr/bin/env node
+/*
+ * 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.
+ *
+ */
+
+/**
+ * Port of qpid-config to JavaScript for Node.js, mainly intended as a demo to
+ * illustrate using QMF2 in JavaScript using the proton.Messenger JS binding.
+ * It illustrates a few things including how to use Messenger completely
+ * asynchronously including using an async request/response pattern with
+ * correlation IDs. It also proves interoperability of AMQP Map, List etc.
+ * between C++ and JavaScript as QMF2 is pretty much all about Lists of Maps.
+ * <p>
+ * The actual QMF2 code is pretty simple as we're just doing a basic getObjects
+ * it's made all the simpler because we can use JavaScript object literals as
+ * the JavaScript binding serialises and deserialises directly between JavaScript
+ * Objects and Lists and the AMQP type system so something that can be quite
+ * involved in languages like C++ and Java becomes quite simple in JavaScript,
+ * though the asynchronous nature of JavaScript provides its own opportunities
+ * for complication best illustrated by the need for the correlator object.
+ */
+
+// Check if the environment is Node.js and if not log an error and exit.
+if (typeof process === 'object' && typeof require === 'function') {
+
+    var qmf = {}; // Create qmf namespace object.
+    qmf.Console = function() { // qmf.Console Constructor.
+        var proton = require("qpid-proton");
+        var message = new proton.Message();
+        var messenger = new proton.Messenger();
+
+        var brokerAddress = '';
+        var replyTo = '';
+
+        /**
+         * The correlator object is a mechanism used to correlate requests with
+         * their aynchronous responses. It might possible be better to make use
+         * of Promises to implement part of this behaviour but a mechanism would
+         * still be needed to correlate a request with its response callback in
+         * order to wrap things up in a Promise, so much of the behaviour of this
+         * object would still be required. In addition it seemed to make sense to
+         * make this QMF2 implementation fairly free of dependencies and using
+         * Promises would require external libraries. Instead the correlator
+         * implements "Promise-like" semantics, you might say a broken Promise :-)
+         * <p>
+         * in particular the request method behaves a *bit* like Promise.all()
+         * though it is mostly fake and takes an array of functions that call
+         * the add() method which is really the method used to associate response
+         * objects by correlationID. The then method is used to register a
+         * listener that will be called when all the requests that have been
+         * registered have received responses.
+         * TODO error/timeout handling.
+         */
+        var correlator = {
+            _resolve: null,
+            _objects: {},
+            add: function(id) {
+                this._objects[id] = {complete: false, list: null};
+            },
+            request: function() {
+                this._resolve = function() {console.log("Warning: No resolver has been set")};
+                return this;
+            },
+            then: function(resolver) {
+                this._resolve = resolver ? resolver : this._resolve;
+            },
+            resolve: function() {
+                var opcode = message.properties['qmf.opcode'];
+                var correlationID = message.getCorrelationID();
+                var resp = this._objects[correlationID];
+                if (opcode === '_query_response') {
+                    if (resp.list) {
+                        Array.prototype.push.apply(resp.list, message.body); // This is faster than concat.
+                    } else {
+                        resp.list = message.body;
+                    }
+        
+                    var partial = message.properties['partial'];
+                    if (!partial) {
+                        resp.complete = true;
+                    }
+        
+                    this._objects[correlationID] = resp;
+                    this._checkComplete();
+                } else if (opcode === '_method_response' || opcode === '_exception') {
+                    resp.list = message.body;
+                    resp.complete = true;
+                    this._objects[correlationID] = resp;
+                    this._checkComplete();
+                } else {
+                    console.error("Bad Message response, qmf.opcode = " + opcode);
+                }
+            },
+            _checkComplete: function() {
+                var response = {};
+                for (var id in this._objects) {
+                    var object = this._objects[id];
+                    if (object.complete) {
+                        response[id] = object.list;
+                    } else {
+                        return;
+                    }
+                }
+    
+                this._objects = {}; // Clear state ready for next call.
+                this._resolve(response.method ? response.method : response);
+            }
+        };  // End of correlator object definition.
+
+        var pumpData = function() {
+            while (messenger.incoming()) {
+                // The second parameter forces Binary payloads to be decoded as
+                // strings this is useful because the broker QMF Agent encodes
+                // strings as AMQP binary unfortunately.
+                var t = messenger.get(message, true);
+                correlator.resolve();
+                messenger.accept(t);
+            }
+    
+            if (messenger.isStopped()) {
+                message.free();
+                messenger.free();
+            }
+        };
+    
+        this.getObjects = function(packageName, className) {
+            message.setAddress(brokerAddress);
+            message.setSubject('broker');
+            message.setReplyTo(replyTo);
+            message.setCorrelationID(className);
+            message.properties = {
+                "routing-key": "broker", // Added for Java Broker
+                "x-amqp-0-10.app-id": "qmf2",
+                "method": "request",
+                "qmf.opcode": "_query_request",
+            };
+            message.body = {
+                "_what": "OBJECT",
+                "_schema_id": {
+                    "_package_name": packageName,
+                    "_class_name": className
+                }
+            };
+    
+            correlator.add(className);
+            messenger.put(message);
+        };
+
+        this.invokeMethod = function(object, method, arguments) {
+            var correlationID = 'method';
+            message.setAddress(brokerAddress);
+            message.setSubject('broker');
+            message.setReplyTo(replyTo);
+            message.setCorrelationID(correlationID);
+            message.properties = {
+                "routing-key": "broker", // Added for Java Broker
+                "x-amqp-0-10.app-id": "qmf2",
+                "method": "request",
+                "qmf.opcode": "_method_request",
+            };
+            message.body = {
+                "_object_id": object._object_id,
+                "_method_name" : method,
+                "_arguments"   : arguments
+            };
+    
+            correlator.add(correlationID);
+            messenger.put(message);
+        };
+
+        this.addConnection = function(addr, callback) {
+            brokerAddress = addr + '/qmf.default.direct';
+            var replyAddress = addr + '/#';
+    
+            messenger.on('subscription', function(subscription) {
+                var subscriptionAddress = subscription.getAddress();
+                var splitAddress = subscriptionAddress.split('/');
+                replyTo = splitAddress[splitAddress.length - 1];
+                callback();
+            });
+
+            messenger.subscribe(replyAddress);
+        }
+
+        this.destroy = function() {
+            messenger.stop(); 
+        }
+
+        this.request = function() {return correlator.request();}
+
+        messenger.on('error', function(error) {console.log(error);});
+        messenger.on('work', pumpData);
+        messenger.setOutgoingWindow(1024);
+        messenger.recv(); // Receive as many messages as messenger can buffer.
+        messenger.start();
+    }; // End of qmf.Console
+
+/************************* qpid-config business logic ************************/
+
+    var brokerAgent = new qmf.Console();
+
+    var _usage =
+    'Usage:  qpid-config [OPTIONS]\n' +
+    '        qpid-config [OPTIONS] exchanges [filter-string]\n' +
+    '        qpid-config [OPTIONS] queues    [filter-string]\n' +
+    '        qpid-config [OPTIONS] add exchange <type> <name> [AddExchangeOptions]\n' +
+    '        qpid-config [OPTIONS] del exchange <name>\n' +
+    '        qpid-config [OPTIONS] add queue <name> [AddQueueOptions]\n' +
+    '        qpid-config [OPTIONS] del queue <name> [DelQueueOptions]\n' +
+    '        qpid-config [OPTIONS] bind   <exchange-name> <queue-name> [binding-key]\n' +
+    '                  <for type xml>     [-f -|filename]\n' +
+    '                  <for type header>  [all|any] k1=v1 [, k2=v2...]\n' +
+    '        qpid-config [OPTIONS] unbind <exchange-name> <queue-name> [binding-key]\n' +
+    '        qpid-config [OPTIONS] reload-acl\n' +
+    '        qpid-config [OPTIONS] add <type> <name> [--argument <property-name>=<property-value>]\n' +
+    '        qpid-config [OPTIONS] del <type> <name>\n' +
+    '        qpid-config [OPTIONS] list <type> [--show-property <property-name>]\n';
+
+    var usage = function() {
+        console.log(_usage);
+        process.exit(-1);
+    };
+
+    var _description =
+    'Examples:\n' +
+    '\n' +
+    '$ qpid-config add queue q\n' +
+    '$ qpid-config add exchange direct d -a localhost:5672\n' +
+    '$ qpid-config exchanges -b 10.1.1.7:10000\n' +
+    '$ qpid-config queues -b guest/guest@broker-host:10000\n' +
+    '\n' +
+    'Add Exchange <type> values:\n' +
+    '\n' +
+    '    direct     Direct exchange for point-to-point communication\n' +
+    '    fanout     Fanout exchange for broadcast communication\n' +
+    '    topic      Topic exchange that routes messages using binding keys with wildcards\n' +
+    '    headers    Headers exchange that matches header fields against the binding keys\n' +
+    '    xml        XML Exchange - allows content filtering using an XQuery\n' +
+    '\n' +
+    '\n' +
+    'Queue Limit Actions:\n' +
+    '\n' +
+    '    none (default) - Use broker\'s default policy\n' +
+    '    reject         - Reject enqueued messages\n' +
+    '    ring           - Replace oldest unacquired message with new\n' +
+    '\n' +
+    'Replication levels:\n' +
+    '\n' +
+    '    none           - no replication\n' +
+    '    configuration  - replicate queue and exchange existence and bindings, but not messages.\n' +
+    '    all            - replicate configuration and messages\n';
+    
+    var _options =
+    'Options:\n' +
+    '  -h, --help            show this help message and exit\n' +
+    '\n' +
+    '  General Options:\n' +
+    '    -t <secs>, --timeout=<secs>\n' +
+    '                        Maximum time to wait for broker connection (in\n' +
+    '                        seconds)\n' +
+    '    -r, --recursive     Show bindings in queue or exchange list\n' +
+    '    -b <address>, --broker=<address>\n' +
+    '                        Address of qpidd broker with syntax:\n' +
+    '                        [username/password@] hostname | ip-address [:<port>]\n' +
+    '    -a <address>, --broker-addr=<address>\n' +
+    /* TODO Connection options
+    '    --sasl-mechanism=<mech>\n' +
+    '                        SASL mechanism for authentication (e.g. EXTERNAL,\n' +
+    '                        ANONYMOUS, PLAIN, CRAM-MD5, DIGEST-MD5, GSSAPI). SASL\n' +
+    '                        automatically picks the most secure available\n' +
+    '                        mechanism - use this option to override.\n' +
+    '    --ssl-certificate=<cert>\n' +
+    '                        Client SSL certificate (PEM Format)\n' +
+    '    --ssl-key=<key>     Client SSL private key (PEM Format)\n' +
+    '    --ha-admin          Allow connection to a HA backup broker.\n' +
+    */
+    '\n' +
+    '  Options for Listing Exchanges and Queues:\n' +
+    '    --ignore-default    Ignore the default exchange in exchange or queue list\n' +
+    '\n' +
+    '  Options for Adding Exchanges and Queues:\n' +
+    '    --alternate-exchange=<aexname>\n' +
+    '                        Name of the alternate-exchange for the new queue or\n' +
+    '                        exchange. Exchanges route messages to the alternate\n' +
+    '                        exchange if they are unable to route them elsewhere.\n' +
+    '                        Queues route messages to the alternate exchange if\n' +
+    '                        they are rejected by a subscriber or orphaned by queue\n' +
+    '                        deletion.\n' +
+    '    --durable           The new queue or exchange is durable.\n' +
+    '    --replicate=<level>\n' +
+    '                        Enable automatic replication in a HA cluster. <level>\n' +
+    '                        is \'none\', \'configuration\' or \'all\').\n' +
+    '\n' +
+    '  Options for Adding Queues:\n' +
+    '    --file-count=<n>    Number of files in queue\'s persistence journal\n' +
+    '    --file-size=<n>     File size in pages (64KiB/page)\n' +
+    '    --max-queue-size=<n>\n' +
+    '                        Maximum in-memory queue size as bytes\n' +
+    '    --max-queue-count=<n>\n' +
+    '                        Maximum in-memory queue size as a number of messages\n' +
+    '    --limit-policy=<policy>\n' +
+    '                        Action to take when queue limit is reached\n' +
+    '    --lvq-key=<key>     Last Value Queue key\n' +
+    '    --generate-queue-events=<n>\n' +
+    '                        If set to 1, every enqueue will generate an event that\n' +
+    '                        can be processed by registered listeners (e.g. for\n' +
+    '                        replication). If set to 2, events will be generated\n' +
+    '                        for enqueues and dequeues.\n' +
+    '    --flow-stop-size=<n>\n' +
+    '                        Turn on sender flow control when the number of queued\n' +
+    '                        bytes exceeds this value.\n' +
+    '    --flow-resume-size=<n>\n' +
+    '                        Turn off sender flow control when the number of queued\n' +
+    '                        bytes drops below this value.\n' +
+    '    --flow-stop-count=<n>\n' +
+    '                        Turn on sender flow control when the number of queued\n' +
+    '                        messages exceeds this value.\n' +
+    '    --flow-resume-count=<n>\n' +
+    '                        Turn off sender flow control when the number of queued\n' +
+    '                        messages drops below this value.\n' +
+    '    --group-header=<header-name>\n' +
+    '                        Enable message groups. Specify name of header that\n' +
+    '                        holds group identifier.\n' +
+    '    --shared-groups     Allow message group consumption across multiple\n' +
+    '                        consumers.\n' +
+    '    --argument=<NAME=VALUE>\n' +
+    '                        Specify a key-value pair to add to queue arguments\n' +
+    '    --start-replica=<broker-url>\n' +
+    '                        Start replication from the same-named queue at\n' +
+    '                        <broker-url>\n' +
+    '\n' +
+    '  Options for Adding Exchanges:\n' +
+    '    --sequence          Exchange will insert a \'qpid.msg_sequence\' field in\n' +
+    '                        the message header\n' +
+    '    --ive               Exchange will behave as an \'initial-value-exchange\',\n' +
+    '                        keeping a reference  to the last message forwarded and\n' +
+    '                        enqueuing that message to newly bound queues.\n' +
+    '\n' +
+    '  Options for Deleting Queues:\n' +
+    '    --force             Force delete of queue even if it\'s currently used or\n' +
+    '                        it\'s not empty\n' +
+    '    --force-if-not-empty\n' +
+    '                        Force delete of queue even if it\'s not empty\n' +
+    '    --force-if-used     Force delete of queue even if it\'s currently used\n' +
+    '\n' +
+    '  Options for Declaring Bindings:\n' +
+    '    -f <file.xq>, --file=<file.xq>\n' +
+    '                        For XML Exchange bindings - specifies the name of a\n' +
+    '                        file containing an XQuery.\n' +
+    '\n' +
+    '  Formatting options for \'list\' action:\n' +
+    '    --show-property=<property-name>\n' +
+    '                        Specify a property of an object to be included in\n' +
+    '                        output\n';
+    
+    var REPLICATE_LEVELS = {"none" : true, "configuration": true, "all": true};
+    var DEFAULT_PROPERTIES = {"exchange": {"name": true, "type": true, "durable": true},
+                                 "queue": {"name": true, "durable": true, "autoDelete": true}};
+    
+    var getValue = function(r) {
+        var value = null;
+        if (r.length === 2) {
+            value = r[1];
+            if (!isNaN(value)) {
+                value = parseInt(value);
+            }
+        }
+    
+        return value;
+    };
+    
+    var config = {
+        _recursive      : false,
+        _host           : 'guest:guest@localhost:5673', // Note 5673 not 5672 as we use WebSocket transport.
+        _connTimeout    : 10,
+        _ignoreDefault  : false,
+        _altern_ex      : null,
+        _durable        : false,
+        _replicate      : null,
+        _if_empty       : true,
+        _if_unused      : true,
+        _fileCount      : null,
+        _fileSize       : null,
+        _maxQueueSize   : null,
+        _maxQueueCount  : null,
+        _limitPolicy    : null,
+        _msgSequence    : false,
+        _lvq_key        : null,
+        _ive            : null,
+        _eventGeneration: null,
+        _file           : null,
+        _flowStopCount  : null,
+        _flowResumeCount: null,
+        _flowStopSize   : null,
+        _flowResumeSize : null,
+        _msgGroupHeader : null,
+        _sharedMsgGroup : false,
+        _extra_arguments: [],
+        _start_replica  : null,
+        _returnCode     : 0,
+        _list_properties: null,
+    
+        getOptions: function() {
+            var options = {};
+            for (var a = 0; a < this._extra_arguments.length; a++) {
+                var r = this._extra_arguments[a].split('=');
+                options[r[0]] = getValue(r);
+            }
+            return options;
+        }
+    };
+    
+    var FILECOUNT = 'qpid.file_count';
+    var FILESIZE  = 'qpid.file_size';
+    var MAX_QUEUE_SIZE  = 'qpid.max_size';
+    var MAX_QUEUE_COUNT  = 'qpid.max_count';
+    var POLICY_TYPE  = 'qpid.policy_type';
+    var LVQ_KEY = 'qpid.last_value_queue_key';
+    var MSG_SEQUENCE = 'qpid.msg_sequence';
+    var IVE = 'qpid.ive';
+    var QUEUE_EVENT_GENERATION = 'qpid.queue_event_generation';
+    var FLOW_STOP_COUNT   = 'qpid.flow_stop_count';
+    var FLOW_RESUME_COUNT = 'qpid.flow_resume_count';
+    var FLOW_STOP_SIZE    = 'qpid.flow_stop_size';
+    var FLOW_RESUME_SIZE  = 'qpid.flow_resume_size';
+    var MSG_GROUP_HDR_KEY = 'qpid.group_header_key';
+    var SHARED_MSG_GROUP  = 'qpid.shared_msg_group';
+    var REPLICATE = 'qpid.replicate';
+    
+    /**
+     * There are various arguments to declare that have specific program
+     * options in this utility. However there is now a generic mechanism for
+     * passing arguments as well. The SPECIAL_ARGS list contains the
+     * arguments for which there are specific program options defined
+     * i.e. the arguments for which there is special processing on add and
+     * list
+    */
+    var SPECIAL_ARGS={};
+    SPECIAL_ARGS[FILECOUNT] = true;
+    SPECIAL_ARGS[FILESIZE] = true;
+    SPECIAL_ARGS[MAX_QUEUE_SIZE] = true;
+    SPECIAL_ARGS[MAX_QUEUE_COUNT] = true;
+    SPECIAL_ARGS[POLICY_TYPE] = true;
+    SPECIAL_ARGS[LVQ_KEY] = true;
+    SPECIAL_ARGS[MSG_SEQUENCE] = true;
+    SPECIAL_ARGS[IVE] = true;
+    SPECIAL_ARGS[QUEUE_EVENT_GENERATION] = true;
+    SPECIAL_ARGS[FLOW_STOP_COUNT] = true;
+    SPECIAL_ARGS[FLOW_RESUME_COUNT] = true;
+    SPECIAL_ARGS[FLOW_STOP_SIZE] = true;
+    SPECIAL_ARGS[FLOW_RESUME_SIZE] = true;
+    SPECIAL_ARGS[MSG_GROUP_HDR_KEY] = true;
+    SPECIAL_ARGS[SHARED_MSG_GROUP] = true;
+    SPECIAL_ARGS[REPLICATE] = true;
+    
+    // Returns a String representation of an ObjectID.
+    var oid = function(id) {
+        return id._agent_epoch + ':' + id._object_name
+    };
+    
+    // Check if the supplied name contains the supplied filter String.
+    var filterMatch = function(name, filter) {
+        if (filter === '') {
+            return true;
+        }
+        if (name.indexOf(filter) === -1) {
+            return false;
+        }
+        return true;
+    };
+    
+    // Take the supplied List of QMF2 Objects and return a Map keyed by ObjectID.
+    var idMap = function(list) {
+        var map = {};
+        for (var i = 0; i < list.length; i++) {
+            var item = list[i];
+            map[oid(item._object_id)] = item;
+        }
+        return map;
+    };
+    
+    // Pretty-print the supplied Object.
+    var renderObject = function(obj, list) {
+        if (!obj) {
+            return '';
+        }
+        var string = '';
+        var addComma = false;
+        for (var prop in obj) {
+            if (addComma) {
+                string += ', ';
+            }
+            if (obj.hasOwnProperty(prop)) {
+                if (list) {
+                    if (SPECIAL_ARGS[prop]) continue;
+                    string += " --argument " + prop + "=" + obj[prop];
+                } else {    
+                    string += "'" + prop + "'" + ": '" + obj[prop] + "'";
+                    addComma = true;
+                }
+            }
+        }
+    
+        if (addComma) {
+            return '{' + string + '}';
+        } else {
+            if (list) {
+                return string;
+            } else {
+                return '';
+            }
+        }
+    };
+    
+    /**
+     * The following methods illustrate the QMF2 class query mechanism which returns
+     * the list of QMF Objects for the specified class that are currently present
+     * on the Broker. The Schema <qpid>/cpp/src/qpid/broker/management-schema.xml
+     * describes the properties and statistics of each Management Object.
+     * <p>
+     * One slightly subtle part of QMF is that certain Objects are associated via
+     * references, for example Binding contains queueRef and exchangeRef, which lets
+     * Objects link to each other using their _object_id property.
+     * <p>
+     * The implementation of these methods attempts to follow the same general flow
+     * as the equivalent method in the "canonical" python based qpid-config version
+     * but has the added complication that JavaScript is entirely asynchronous.
+     * The approach that has been taken is to use the correlator object that lets a
+     * callback function be registered via the "then" method and actually calls the
+     * callback when all of the requests specified in the request method have
+     * returned their results (which get passed as the callback parameter).
+     */
+    
+    var overview = function() {
+        brokerAgent.request(
+            // Send the QMF query requests for the specified classes.
+            brokerAgent.getObjects('org.apache.qpid.broker', 'queue'),
+            brokerAgent.getObjects('org.apache.qpid.broker', 'exchange')
+        ).then(function(objects) {
+            var exchanges = objects.exchange;
+            var queues = objects.queue;
+            console.log("Total Exchanges: " + exchanges.length);
+            var etype = {};
+            for (var i = 0; i < exchanges.length; i++) {
+                var exchange = exchanges[i]._values;
+                if (!etype[exchange.type]) {
+                    etype[exchange.type] = 1;
+                } else {
+                    etype[exchange.type]++;
+                }
+            }
+            for (var typ in etype) {
+                var pad = Array(16 - typ.length).join(' ');
+                console.log(pad + typ + ": " + etype[typ]);
+            }
+    
+            console.log("\n   Total Queues: " + queues.length);
+            var durable = 0;
+            for (var i = 0; i < queues.length; i++) {
+                var queue = queues[i]._values;
+                if (queue.durable) {
+                    durable++;
+                }
+            }
+            console.log("        durable: " + durable);
+            console.log("    non-durable: " + (queues.length - durable));
+            brokerAgent.destroy();
+        });
+    };
+    
+    var exchangeList = function(filter) {
+        brokerAgent.request(
+            // Send the QMF query requests for the specified classes.
+            brokerAgent.getObjects('org.apache.qpid.broker', 'exchange')
+        ).then(function(objects) {
+            var exchanges = objects.exchange;
+            var exMap = idMap(exchanges);
+            var caption1 = "Type      ";
+            var caption2 = "Exchange Name";
+            var maxNameLen = caption2.length;
+            var found = false;
+            for (var i = 0; i < exchanges.length; i++) {
+                var exchange = exchanges[i]._values;
+                if (filterMatch(exchange.name, filter)) {
+                    if (exchange.name.length > maxNameLen) {
+                        maxNameLen = exchange.name.length;
+                    }
+                    found = true;
+                }
+            }
+            if (!found) {
+                config._returnCode = 1;
+                return;
+            }
+    
+            var pad = Array(maxNameLen + 1 - caption2.length).join(' ');
+            console.log(caption1 + caption2 + pad + "  Attributes");
+            console.log(Array(maxNameLen + caption1.length + 13).join('='));
+    
+            for (var i = 0; i < exchanges.length; i++) {
+                var exchange = exchanges[i]._values;
+                if (config._ignoreDefault && !exchange.name) continue;
+                if (filterMatch(exchange.name, filter)) {
+                    var pad1 = Array(11 - exchange.type.length).join(' ');
+                    var pad2 = Array(maxNameLen + 2 - exchange.name.length).join(' ');
+                    var string = exchange.type + pad1 + exchange.name + pad2;
+                    var args = exchange.arguments ? exchange.arguments : {};
+                    if (exchange.durable) {
+                        string += ' --durable';
+                    }
+                    if (args[REPLICATE]) {
+                        string += ' --replicate=' + args[REPLICATE];
+                    }
+                    if (args[MSG_SEQUENCE]) {
+                        string += ' --sequence';
+                    }
+                    if (args[IVE]) {
+                        string += ' --ive';
+                    }
+                    if (exchange.altExchange) {
+                        string += ' --alternate-exchange=' + exMap[oid(exchange.altExchange)]._values.name;
+                    }
+                    console.log(string);
+                }
+            }
+            brokerAgent.destroy();
+        });
+    };
+    
+    var exchangeListRecurse = function(filter) {
+        brokerAgent.request(
+            // Send the QMF query requests for the specified classes.
+            brokerAgent.getObjects('org.apache.qpid.broker', 'queue'),
+            brokerAgent.getObjects('org.apache.qpid.broker', 'exchange'),
+            brokerAgent.getObjects('org.apache.qpid.broker', 'binding')
+        ).then(function(objects) {
+            var exchanges = objects.exchange;
+            var bindings = objects.binding;
+            var queues = idMap(objects.queue);
+    
+            for (var i = 0; i < exchanges.length; i++) {
+                var exchange = exchanges[i];
+                var exchangeId = oid(exchange._object_id);
+                exchange = exchange._values;
+    
+                if (config._ignoreDefault && !exchange.name) continue;
+                if (filterMatch(exchange.name, filter)) {
+                    console.log("Exchange '" + exchange.name + "' (" + exchange.type + ")");
+                    for (var j = 0; j < bindings.length; j++) {
+                        var bind = bindings[j]._values;
+                        var exchangeRef = oid(bind.exchangeRef);
+    
+                        if (exchangeRef === exchangeId) {
+                            var queue = queues[oid(bind.queueRef)];
+                            var queueName = queue ? queue._values.name : "<unknown>";
+                            console.log("    bind [" + bind.bindingKey + "] => " + queueName + 
+                                        " " + renderObject(bind.arguments));
+                        }   
+                    }
+                }
+            }
+            brokerAgent.destroy();
+        });
+    };
+    
+    var queueList = function(filter) {
+        brokerAgent.request(
+            // Send the QMF query requests for the specified classes.
+            brokerAgent.getObjects('org.apache.qpid.broker', 'queue'),
+            brokerAgent.getObjects('org.apache.qpid.broker', 'exchange')
+        ).then(function(objects) {
+            var queues = objects.queue;
+            var exMap = idMap(objects.exchange);
+            var caption = "Queue Name";
+            var maxNameLen = caption.length;
+            var found = false;
+            for (var i = 0; i < queues.length; i++) {
+                var queue = queues[i]._values;
+                if (filterMatch(queue.name, filter)) {
+                    if (queue.name.length > maxNameLen) {
+                        maxNameLen = queue.name.length;
+                    }
+                    found = true;
+                }
+            }
+            if (!found) {
+                config._returnCode = 1;
+                return;
+            }
+    
+            var pad = Array(maxNameLen + 1 - caption.length).join(' ');
+            console.log(caption + pad + "  Attributes");
+            console.log(Array(maxNameLen + caption.length + 3).join('='));
+    
+            for (var i = 0; i < queues.length; i++) {
+                var queue = queues[i]._values;
+                if (filterMatch(queue.name, filter)) {
+                    var pad2 = Array(maxNameLen + 2 - queue.name.length).join(' ');
+                    var string = queue.name + pad2;
+                    var args = queue.arguments ? queue.arguments : {};
+                    if (queue.durable) {
+                        string += ' --durable';
+                    }
+                    if (args[REPLICATE]) {
+                        string += ' --replicate=' + args[REPLICATE];
+                    }
+                    if (queue.autoDelete) {
+                        string += ' auto-del';
+                    }
+                    if (queue.exclusive) {
+                        string += ' excl';
+                    }
+                    if (args[FILESIZE]) {
+                        string += ' --file-size=' + args[FILESIZE];
+                    }
+                    if (args[FILECOUNT]) {
+                        string += ' --file-count=' + args[FILECOUNT];
+                    }
+                    if (args[MAX_QUEUE_SIZE]) {
+                        string += ' --max-queue-size=' + args[MAX_QUEUE_SIZE];
+                    }
+                    if (args[MAX_QUEUE_COUNT]) {
+                        string += ' --max-queue-count=' + args[MAX_QUEUE_COUNT];
+                    }
+                    if (args[POLICY_TYPE]) {
+                        string += ' --limit-policy=' + args[POLICY_TYPE].replace("_", "-");
+                    }
+                    if (args[LVQ_KEY]) {
+                        string += ' --lvq-key=' + args[LVQ_KEY];
+                    }
+                    if (args[QUEUE_EVENT_GENERATION]) {
+                        string += ' --generate-queue-events=' + args[QUEUE_EVENT_GENERATION];
+                    }
+                    if (queue.altExchange) {
+                        string += ' --alternate-exchange=' + exMap[oid(queue.altExchange)]._values.name;
+                    }
+                    if (args[FLOW_STOP_SIZE]) {
+                        string += ' --flow-stop-size=' + args[FLOW_STOP_SIZE];
+                    }
+                    if (args[FLOW_RESUME_SIZE]) {
+                        string += ' --flow-resume-size=' + args[FLOW_RESUME_SIZE];
+                    }
+                    if (args[FLOW_STOP_COUNT]) {
+                        string += ' --flow-stop-count=' + args[FLOW_STOP_COUNT];
+                    }
+                    if (args[FLOW_RESUME_COUNT]) {
+                        string += ' --flow-resume-count=' + args[FLOW_RESUME_COUNT];
+                    }
+                    if (args[MSG_GROUP_HDR_KEY]) {
+                        string += ' --group-header=' + args[MSG_GROUP_HDR_KEY];
+                    }
+                    if (args[SHARED_MSG_GROUP] === 1) {
+                        string += ' --shared-groups';
+                    }
+                    string += ' ' + renderObject(args, true);
+                    console.log(string);
+                }
+            }
+            brokerAgent.destroy();
+        });
+    };
+    
+    var queueListRecurse = function(filter) {
+        brokerAgent.request(
+            // Send the QMF query requests for the specified classes.
+            brokerAgent.getObjects('org.apache.qpid.broker', 'queue'),
+            brokerAgent.getObjects('org.apache.qpid.broker', 'exchange'),
+            brokerAgent.getObjects('org.apache.qpid.broker', 'binding')
+        ).then(function(objects) {
+            var queues = objects.queue;
+            var bindings = objects.binding;
+            var exchanges = idMap(objects.exchange);
+    
+            for (var i = 0; i < queues.length; i++) {
+                var queue = queues[i];
+                var queueId = oid(queue._object_id);
+                queue = queue._values;
+    
+                if (filterMatch(queue.name, filter)) {
+                    console.log("Queue '" + queue.name + "'");
+                    for (var j = 0; j < bindings.length; j++) {
+                        var bind = bindings[j]._values;
+                        var queueRef = oid(bind.queueRef);
+    
+                        if (queueRef === queueId) {
+                            var exchange = exchanges[oid(bind.exchangeRef)];
+                            var exchangeName = "<unknown>";
+                            if (exchange) {
+                                exchangeName = exchange._values.name;
+                                if (exchangeName === '') {
+                                    if (config._ignoreDefault) continue;
+                                    exchangeName = "''";
+                                }
+                            }
+    
+                            console.log("    bind [" + bind.bindingKey + "] => " + exchangeName + 
+                                        " " + renderObject(bind.arguments));
+                        }   
+                    }
+                }
+            }
+            brokerAgent.destroy();
+        });
+    };
+    
+    /**
+     * The following methods implement adding and deleting various Broker Management
+     * Objects via QMF. Although <qpid>/cpp/src/qpid/broker/management-schema.xml
+     * describes the basic method schema, for example:
+     *   <method name="create" desc="Create an object of the specified type">
+     *     <arg name="type" dir="I" type="sstr" desc="The type of object to create"/>
+     *     <arg name="name" dir="I" type="sstr" desc="The name of the object to create"/>
+     *     <arg name="properties" dir="I" type="map" desc="Type specific object properties"/>
+     *     <arg name="strict" dir="I" type="bool" desc="If specified, treat unrecognised object properties as an error"/    >
+     *   </method>
+     *
+     *   <method name="delete" desc="Delete an object of the specified type">
+     *     <arg name="type" dir="I" type="sstr" desc="The type of object to delete"/>
+     *     <arg name="name" dir="I" type="sstr" desc="The name of the object to delete"/>
+     *     <arg name="options" dir="I" type="map" desc="Type specific object options for deletion"/>
+     *   </method>
+     *
+     * What the schema doesn't do however is to explain what the properties/options
+     * Map values actually mean, unfortunately these aren't documented anywhere so
+     * the only option is to look in the code, the best place to look is in:
+     * <qpid>/cpp/src/qpid/broker/Broker.cpp, the method Broker::ManagementMethod is
+     * the best place to start, then Broker::createObject and Broker::deleteObject
+     * even then it's pretty hard to figure out all that is possible.
+     */
+    
+    var handleMethodResponse = function(response, dontStop) {
+        if (response._arguments) {
+            //console.log(response._arguments);
+        } if (response._values) {
+            console.error("Exception from Agent: " + renderObject(response._values));
+        }
+        // Mostly we want to stop the Messenger Event loop and exit when a QMF method
+        // returns, but sometimes we don't, the dontStop flag prevents this behaviour.
+        if (!dontStop) {
+            brokerAgent.destroy();
+        }
+    }
+    
+    var addExchange = function(args) {
+        if (args.length < 2) {
+            usage();
+        }
+    
+        var etype = args[0];
+        var ename = args[1];
+        var declArgs = {};
+    
+        declArgs['exchange-type'] = etype;
+    
+        for (var a = 0; a < config._extra_arguments.length; a++) {
+            var r = config._extra_arguments[a].split('=');
+            declArgs[r[0]] = getValue(r);
+        }
+    
+        if (config._msgSequence) {
+            declArgs[MSG_SEQUENCE] = 1;
+        }
+    
+        if (config._ive) {
+            declArgs[IVE] = 1;
+        }
+    
+        if (config._altern_ex) {
+            declArgs['alternate-exchange'] = config._altern_ex;
+        }
+    
+        if (config._durable) {
+            declArgs['durable'] = 1;
+        }
+    
+        if (config._replicate) {
+            declArgs[REPLICATE] = config._replicate;
+        }
+    
+        brokerAgent.request(
+            // We invoke the CRUD methods on the broker object.
+            brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
+        ).then(function(objects) {
+            var broker = objects.broker[0];
+            brokerAgent.request(
+                brokerAgent.invokeMethod(broker, 'create', {
+                    "type":      "exchange",
+                    "name":       ename,
+                    "properties": declArgs,
+                    "strict":     true})
+            ).then(handleMethodResponse);
+        });
+    };
+    
+    var delExchange = function(args) {
+        if (args.length < 1) {
+            usage();
+        }
+    
+        var ename = args[0];
+    
+        brokerAgent.request(
+            // We invoke the CRUD methods on the broker object.
+            brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
+        ).then(function(objects) {
+            var broker = objects.broker[0];
+            brokerAgent.request(
+                brokerAgent.invokeMethod(broker, 'delete', {
+                    "type":   "exchange",
+                    "name":    ename})
+            ).then(handleMethodResponse);
+        });
+    };
+    
+    var addQueue = function(args) {
+        if (args.length < 1) {
+            usage();
+        }
+    
+        var qname = args[0];
+        var declArgs = {};
+    
+        for (var a = 0; a < config._extra_arguments.length; a++) {
+            var r = config._extra_arguments[a].split('=');
+            declArgs[r[0]] = getValue(r);
+        }
+    
+        if (config._durable) {
+            // allow the default fileCount and fileSize specified 
+            // in qpid config file to take prededence
+            if (config._fileCount) {
+                declArgs[FILECOUNT] = config._fileCount;
+            }
+            if (config._fileSize) {
+                declArgs[FILESIZE]  = config._fileSize;
+            }
+        }
+    
+        if (config._maxQueueSize != null) {
+            declArgs[MAX_QUEUE_SIZE] = config._maxQueueSize;
+        }
+    
+        if (config._maxQueueCount != null) {
+            declArgs[MAX_QUEUE_COUNT] = config._maxQueueCount;
+        }
+        
+        if (config._limitPolicy) {
+            if (config._limitPolicy === 'none') {
+            } else if (config._limitPolicy === 'reject') {
+                declArgs[POLICY_TYPE] = 'reject';
+            } else if (config._limitPolicy === 'ring') {
+                declArgs[POLICY_TYPE] = 'ring';
+            }
+        }
+    
+        if (config._lvq_key) {
+            declArgs[LVQ_KEY] = config._lvq_key;
+        }
+    
+        if (config._eventGeneration) {
+            declArgs[QUEUE_EVENT_GENERATION] = config._eventGeneration;
+        }
+    
+        if (config._flowStopSize != null) {
+            declArgs[FLOW_STOP_SIZE] = config._flowStopSize;
+        }
+    
+        if (config._flowResumeSize != null) {
+            declArgs[FLOW_RESUME_SIZE] = config._flowResumeSize;
+        }
+    
+        if (config._flowStopCount != null) {
+            declArgs[FLOW_STOP_COUNT] = config._flowStopCount;
+        }
+    
+        if (config._flowResumeCount != null) {
+            declArgs[FLOW_RESUME_COUNT] = config._flowResumeCount;
+        }
+    
+        if (config._msgGroupHeader) {
+            declArgs[MSG_GROUP_HDR_KEY] = config._msgGroupHeader;
+        }
+    
+        if (config._sharedMsgGroup) {
+            declArgs[SHARED_MSG_GROUP] = 1;
+        }
+    
+        if (config._altern_ex) {
+            declArgs['alternate-exchange'] = config._altern_ex;
+        }
+    
+        if (config._durable) {
+            declArgs['durable'] = 1;
+        }
+    
+        if (config._replicate) {
+            declArgs[REPLICATE] = config._replicate;
+        }
+    
+        // This block is a little complex and untidy, the real issue is that the
+        // correlator object isn't as good as a real Promise and doesn't support
+        // chaining of "then" calls, so where we have complex dependencies we still
+        // get somewhat into "callback hell". TODO improve the correlator.
+        brokerAgent.request(
+            // We invoke the CRUD methods on the broker object.
+            brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
+        ).then(function(objects) {
+            var broker = objects.broker[0];
+            brokerAgent.request(
+                brokerAgent.invokeMethod(broker, 'create', {
+                    "type":      "queue",
+                    "name":       qname,
+                    "properties": declArgs,
+                    "strict":     true})
+            ).then(function(response) {
+                if (config._start_replica) {
+                    handleMethodResponse(response, true); // The second parameter prevents exiting.
+                    // TODO test this stuff!
+                    brokerAgent.request(
+                        brokerAgent.getObjects('org.apache.qpid.ha', 'habroker') // Not sure if this is correct
+                    ).then(function(objects) {
+                        if (objects.habroker.length > 0) {
+                            var habroker = objects.habroker[0];
+                            brokerAgent.request(
+                                brokerAgent.invokeMethod(habroker, 'replicate', {
+                                    "broker": config._start_replica,
+                                    "queue":  qname})
+                            ).then(handleMethodResponse);
+                        } else {
+                            brokerAgent.destroy();
+                        }
+                    });
+                } else {
+                    handleMethodResponse(response);
+                }
+            });
+        });
+    };
+    
+    var delQueue = function(args) {
+        if (args.length < 1) {
+            usage();
+        }
+    
+        var qname = args[0];
+    
+        brokerAgent.request(
+            // We invoke the CRUD methods on the broker object.
+            brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
+        ).then(function(objects) {
+            var broker = objects.broker[0];
+            brokerAgent.request(
+                brokerAgent.invokeMethod(broker, 'delete', {
+                    "type":   "queue",
+                    "name":    qname,
+                    "options": {"if_empty":  config._if_empty,
+                                "if_unused": config._if_unused}})
+            ).then(handleMethodResponse);
+        });
+    };
+    
+    var snarf_header_args = function(args) {
+        if (args.length < 2) {
+            console.log("Invalid args to bind headers: need 'any'/'all' plus conditions");
+            return false;
+        }
+    
+        var op = args[0];
+        if (op === 'all' || op === 'any') {
+            kv = {};
+            var bindings = Array.prototype.slice.apply(args, [1]);
+            for (var i = 0; i < bindings.length; i++) {
+                var binding = bindings[i];
+                binding = binding.split(",")[0];
+                binding = binding.split("=");
+                kv[binding[0]] = binding[1];
+            }
+            kv['x-match'] = op;
+            return kv;
+        } else {
+            console.log("Invalid condition arg to bind headers, need 'any' or 'all', not '" + op + "'");
+            return false;
+        }
+    };
+    
+    var bind = function(args) {
+        if (args.length < 2) {
+            usage();
+        }
+    
+        var ename = args[0];
+        var qname = args[1];
+        var key   = '';
+    
+        if (args.length > 2) {
+            key = args[2];
+        }
+    
+        brokerAgent.request(
+            // We invoke the CRUD methods on the broker object.
+            brokerAgent.getObjects('org.apache.qpid.broker', 'broker'),
+            brokerAgent.getObjects('org.apache.qpid.broker', 'exchange') // Get exchanges to look up exchange type.
+        ).then(function(objects) {
+            var exchanges = objects.exchange;
+    
+            var etype = '';
+            for (var i = 0; i < exchanges.length; i++) {
+                var exchange = exchanges[i]._values;
+                if (exchange.name === ename) {
+                    etype = exchange.type;
+                    break;
+                }
+            }
+    
+            // type of the xchg determines the processing of the rest of
+            // argv.  if it's an xml xchg, we want to find a file
+            // containing an x-query, and pass that.  if it's a headers
+            // exchange, we need to pass either "any" or all, followed by a
+            // map containing key/value pairs.  if neither of those, extra
+            // args are ignored.
+            var declArgs = {};
+            if (etype === 'xml') {
+    
+    
+            } else if (etype === 'headers') {
+                declArgs = snarf_header_args(Array.prototype.slice.apply(args, [3]));
+            }
+    //console.log(declArgs);
+    
+            if (typeof declArgs !== 'object') {
+                process.exit(1);
+            }
+    
+            var broker = objects.broker[0];
+            brokerAgent.request(
+                brokerAgent.invokeMethod(broker, 'create', {
+                    "type":   "binding",
+                    "name":    ename + '/' + qname + '/' + key,
+                    "properties": declArgs,
+                    "strict":     true})
+            ).then(handleMethodResponse);
+        });
+    
+    /*
+    
+            ok = True
+            _args = {}
+            if not res:
+                pass
+            elif res.type == "xml":
+                # this checks/imports the -f arg
+                [ok, xquery] = snarf_xquery_args()
+                _args = { "xquery" : xquery }
+            else:
+                if res.type == "headers":
+                    [ok, op, kv] = snarf_header_args(args[3:])
+                    _args = kv
+                    _args["x-match"] = op
+    
+            if not ok:
+                sys.exit(1)
+    
+            self.broker.bind(ename, qname, key, _args)
+    */
+    
+    };
+    
+    var unbind = function(args) {
+        if (args.length < 2) {
+            usage();
+        }
+    
+        var ename = args[0];
+        var qname = args[1];
+        var key   = '';
+    
+        if (args.length > 2) {
+            key = args[2];
+        }
+    
+        brokerAgent.request(
+            // We invoke the CRUD methods on the broker object.
+            brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
+        ).then(function(objects) {
+            var broker = objects.broker[0];
+            brokerAgent.request(
+                brokerAgent.invokeMethod(broker, 'delete', {
+                    "type":   "binding",
+                    "name":    ename + '/' + qname + '/' + key})
+            ).then(handleMethodResponse);
+        });
+    };
+
+    /**
+     * The following methods are "generic" create and delete methods to for arbitrary
+     * Management Objects e.g. Incoming, Outgoing, Domain, Topic, QueuePolicy,
+     * TopicPolicy etc. use --argument k1=v1 --argument k2=v2 --argument k3=v3 to
+     * pass arbitrary arguments as key/value pairs to the Object being created/deleted,
+     * for example to add a topic object that uses the fanout exchange:
+     * ./qpid-config.js add topic fanout --argument exchange=amq.fanout \
+     * --argument qpid.max_size=1000000 --argument qpid.policy_type=ring
+     */
+    
+    var createObject = function(type, name, args) {
+        brokerAgent.request(
+            // We invoke the CRUD methods on the broker object.
+            brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
+        ).then(function(objects) {
+            var broker = objects.broker[0];
+            brokerAgent.request(
+                // Create an object of the specified type.
+                brokerAgent.invokeMethod(broker, 'create', {
+                    "type":       type,
+                    "name":       name,
+                    "properties": args,
+                    "strict":     true})
+            ).then(handleMethodResponse);
+        });
+    };
+    
+    var deleteObject = function(type, name, args) {
+        brokerAgent.request(
+            // We invoke the CRUD methods on the broker object.
+            brokerAgent.getObjects('org.apache.qpid.broker', 'broker')
+        ).then(function(objects) {
+            var broker = objects.broker[0];
+            brokerAgent.request(
+                // Create an object of the specified type and name.
+                brokerAgent.invokeMethod(broker, 'delete', {
+                    "type":    type,
+                    "name":    name,
+                    "options": args})
+            ).then(handleMethodResponse);
+        });
+    };
+    
+    /**
+     * This is a "generic" mechanism for listing arbitrary Management Objects.
+     */
+    var listObjects = function(type) {
+        brokerAgent.request(
+            brokerAgent.getObjects('org.apache.qpid.broker', type)
+        ).then(function(objects) {
+            // The correlator passes an object containing responses for all of the
+            // supplied requests so we index it by the supplied type to get our response.
+            objects = objects[type];
+    
+            // Collect available attributes, stringify the values and compute the max
+            // length of the value of each attribute so that we can later create a table.
+            var attributes = {};
+            var lengths = {};
+            for (var i = 0; i < objects.length; i++) {
+                var object = objects[i];
+                object = object._values;
+                for (var prop in object) {
+                    if (typeof object[prop] === 'object') { // Stringify Object properties.
+                        // Check if property is an ObjectID (reference property),
+                        // if so replace with the "name" part of the OID.
+                        if (object[prop]['_object_name']) {
+                            var parts = object[prop]['_object_name'].split(':');
+                            object[prop] = parts[parts.length - 1];
+                        } else {
+                            // Stringify general Object properties.
+                            object[prop] = renderObject(object[prop]);
+                        }
+                    } else {
+                        object[prop] = object[prop].toString(); // Stringify other property types.
+                    }
+    
+                    if (!lengths[prop] || object[prop].length > lengths[prop]) { // Compute lengths.
+                        lengths[prop] = object[prop].length > prop.length ? object[prop].length : prop.length;
+                    }
+    
+                    if (!config._list_properties || config._list_properties[prop]) { // Do we want this property?
+                        attributes[prop] = true;
+                    }
+                }
+            }
+    
+            if (!config._list_properties && DEFAULT_PROPERTIES[type]) {
+                attributes = DEFAULT_PROPERTIES[type];
+            }
+    
+            // Using the information we've previously prepared now render a table
+            // showing the required property values.
+            var desired = [];
+            var header = ''; // Table header showing the property names.
+            if (attributes['name']) {
+                desired.push('name');
+                delete attributes['name'];
+                header += 'name' + Array(lengths['name'] + 2 - 4).join(' ');
+            }
+    
+            for (var prop in attributes) {
+                desired.push(prop);
+                header += prop + Array(lengths[prop] + 2 - prop.length).join(' ');
+            }
+    
+            console.log("Objects of type '" + type + "'");
+            console.log(header);
+            console.log(Array(header.length).join('='));
+            for (var i = 0; i < objects.length; i++) {
+                var object = objects[i];
+                object = object._values;
+                var string = '';
+                for (var j = 0; j < desired.length; j++) {
+                    var key = desired[j];
+                    string += object[key] + Array(lengths[key] + 2 - object[key].length).join(' ');
+                }
+    
+                console.log(string);
+            }
+    
+            brokerAgent.destroy();
+        });
+    };
+    
+    var reloadAcl = function() {
+        brokerAgent.request(
+            brokerAgent.getObjects('org.apache.qpid.acl', 'acl')
+        ).then(function(objects) {
+            if (objects.acl.length > 0) {
+                var acl = objects.acl[0];
+                brokerAgent.request(
+                    // Create an object of the specified type.
+                    brokerAgent.invokeMethod(acl, 'reloadACLFile', {})
+                ).then(handleMethodResponse);
+            } else {
+                console.log("Failed: No ACL Loaded in Broker");
+                brokerAgent.destroy();
+            }
+        });
+    };
+    
+    
+    /********************* process command line options **********************/
+    
+    var params = [];
+    var extra_arguments = [];
+    var args = process.argv.slice(2);
+    if (args.length > 0) {
+        if (args[0] === '-h' || args[0] === '--help') {
+            console.log(_usage);
+            console.log(_description);
+            console.log(_options);
+            process.exit(0);
+        }
+    
+        for (var i = 0; i < args.length; i++) {
+            var arg = args[i];
+            if (arg === '-r' || arg === '--recursive') {
+                config._recursive = true;
+            } else if (arg === '--ignore-default') {
+                config._ignoreDefault = true;
+            } else if (arg === '--durable') {
+                config._durable = true;
+            } else if (arg === '--shared-groups') {
+                config._sharedMsgGroup = true;
+            } else if (arg === '--sequence') {
+                config._sequence = true;
+            } else if (arg === '--ive') {
+                config._ive = true;
+            } else if (arg === '--force') {
+                config._if_empty = false;
+                config._if_unused = false;
+            } else if (arg === '--force-if-not-empty') {
+                config._if_empty = false;
+            } else if (arg === '--force-if-used') {
+                config._if_unused = false;
+            } else if (arg === '--sequence') {
+                config._msgSequence = true;
+            } else if (arg.charAt(0) === '-') {
+                i++;
+                var val = args[i];
+                if (arg === '-t' || arg === '--timeout') {
+                    config._connTimeout = parseInt(val);
+                    if (config._connTimeout === 0) {
+                        config._connTimeout = null;
+                    }
+                } else if (arg === '-b' || arg === '--broker' || arg === '-a' || arg === '--broker-addr') {
+                    if (val != null) {
+                        config._host = val;
+                    }
+                } else if (arg === '--alternate-exchange') {
+                    config._altern_ex = val;
+                } else if (arg === '--replicate') {
+                    if (!REPLICATE_LEVELS[val]) {
+                        console.error("Invalid replication level " + val + ", should be one of 'none', 'configuration'  or 'all'");
+                    }
+                    config._replicate = val;
+                } else if (arg === '--file-count') {
+                    config._fileCount = parseInt(val);
+                } else if (arg === '--file-size') {
+                    config._fileSize = parseInt(val);
+                } else if (arg === '--max-queue-size') {
+                    config._maxQueueSize = parseInt(val);
+                } else if (arg === '--max-queue-count') {
+                    config._maxQueueCount = parseInt(val);
+                } else if (arg === '--limit-policy') {
+                    config._limitPolicy = val;
+                } else if (arg === '--lvq-key') {
+                    config._lvq_key = val;
+                } else if (arg === '--generate-queue-events') {
+                    config._eventGeneration = parseInt(val);
+                } else if (arg === '--flow-stop-size') {
+                    config._flowStopSize = parseInt(val);
+                } else if (arg === '--flow-resume-size') {
+                    config._flowResumeSize = parseInt(val);
+                } else if (arg === '--flow-stop-count') {
+                    config._flowStopCount = parseInt(val);
+                } else if (arg === '--flow-resume-count') {
+                    config._flowResumeCount = parseInt(val);
+                } else if (arg === '--group-header') {
+                    config._msgGroupHeader = val;
+                } else if (arg === '--argument') {
+                    extra_arguments.push(val);
+                } else if (arg === '--start-replica') {
+                    config._start_replica = val;
+                } else if (arg === '--f' || arg === '--file') { // TODO Won't work in node.js
+                    config._file = val;
+                } else if (arg === '--show-property') {
+                    if (config._list_properties === null) {
+                        config._list_properties = {};
+                    }
+                    config._list_properties[val] = true;
+                }
+            } else {
+                params.push(arg);
+            }
+        }
+    }
+    
+    config._extra_arguments = extra_arguments;
+    
+    // The command only *actually* gets called when the QMF connection has actually
+    // been established so we wrap up the function we want to get called in a lambda.
+    var command = function() {overview();};
+    if (params.length > 0) {
+        var cmd = params[0];
+        var modifier = '';
+        if (params.length > 1) {
+            modifier = params[1];
+        }
+    
+        if (cmd === 'exchanges') {
+            if (config._recursive) {
+                command = function() {exchangeListRecurse(modifier);};
+            } else {
+                command = function() {exchangeList(modifier);};
+            }
+        } else if (cmd === 'queues') {
+            if (config._recursive) {
+                command = function() {queueListRecurse(modifier);};
+            } else {
+                command = function() {queueList(modifier);};
+            }
+        } else if (cmd === 'add') {
+            if (modifier === 'exchange') {
+                command = function() {addExchange(Array.prototype.slice.apply(params, [2]));};
+            } else if (modifier === 'queue') {
+                command = function() {addQueue(Array.prototype.slice.apply(params, [2]));};
+            } else if (params.length > 2) {
+                command = function() {createObject(modifier, params[2], config.getOptions());};
+            } else {
+                usage();
+            }
+        } else if (cmd === 'del') {
+            if (modifier === 'exchange') {
+                command = function() {delExchange(Array.prototype.slice.apply(params, [2]));};
+            } else if (modifier === 'queue') {
+                command = function() {delQueue(Array.prototype.slice.apply(params, [2]));};
+            } else if (params.length > 2) {
+                command = function() {deleteObject(modifier, params[2], {});};
+            } else {
+                usage();
+            }
+        } else if (cmd === 'bind') {
+            command = function() {bind(Array.prototype.slice.apply(params, [1]));};
+        } else if (cmd === 'unbind') {
+            command = function() {unbind(Array.prototype.slice.apply(params, [1]));};
+        } else if (cmd === 'reload-acl') {
+            command = function() {reloadAcl();};
+        } else if (cmd === 'list' && params.length > 1) {
+            command = function() {listObjects(modifier);};
+        } else {
+            usage();
+        }
+    }
+    
+    //console.log(config._host);
+    brokerAgent.addConnection(config._host, command);    
+} else {
+    console.error("qpid-config.js should be run in Node.js");
+}
+
diff --git a/examples/messenger/javascript/recv.js b/examples/messenger/javascript/recv.js
new file mode 100644
index 0000000..ab5fcf1
--- /dev/null
+++ b/examples/messenger/javascript/recv.js
@@ -0,0 +1,69 @@
+#!/usr/bin/env node
+/*
+ * 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.
+ *
+ */
+
+// Check if the environment is Node.js and if not log an error and exit.
+if (typeof process === 'object' && typeof require === 'function') {
+    var proton = require("qpid-proton");
+
+    var address = "amqp://~0.0.0.0";
+    var message = new proton.Message();
+    var messenger = new proton.Messenger();
+
+    var pumpData = function() {
+        while (messenger.incoming()) {
+            var t = messenger.get(message);
+
+            console.log("Address: " + message.getAddress());
+            console.log("Subject: " + message.getSubject());
+    
+            // body is the body as a native JavaScript Object, useful for most real cases.
+            //console.log("Content: " + message.body);
+    
+            // data is the body as a proton.Data Object, used in this case because
+            // format() returns exactly the same representation as recv.c
+            console.log("Content: " + message.data.format());
+    
+            messenger.accept(t);
+        }
+    };
+
+    var args = process.argv.slice(2);
+    if (args.length > 0) {
+        if (args[0] === '-h' || args[0] === '--help') {
+            console.log("Usage: node recv.js <addr> (default " + address + ")");
+            process.exit(0);
+        }
+    
+        address = args[0];
+    }
+    
+    messenger.setIncomingWindow(1024);
+    
+    messenger.on('error', function(error) {console.log(error);});
+    messenger.on('work', pumpData);
+    messenger.recv(); // Receive as many messages as messenger can buffer.
+    messenger.start();
+
+    messenger.subscribe(address);
+} else {
+    console.error("recv.js should be run in Node.js");
+}
+
diff --git a/examples/messenger/javascript/send.html b/examples/messenger/javascript/send.html
new file mode 100644
index 0000000..c61e3f2
--- /dev/null
+++ b/examples/messenger/javascript/send.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html> <!-- HTML5 doctype -->
+
+<!--
+  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.
+-->
+
+<html>
+
+<head>
+	<title>Simple Proton Messenger Send Example</title>
+	<meta http-equiv="content-type" content="text/html;charset=utf-8" />
+
+<!--
+  Import the Messenger Binding proton.js. Note that this simple example pulls
+  it from the node_modules/qpid-proton/lib, which is created by the build process
+  so that the node.js based examples "just work", in a real Web App you would
+  clearly need to copy the proton.js to your own server.
+
+  In actual fact the CMake build actually builds proton.js into the directory:
+  <build>/proton-c/bindings/javascript
+  where <build> is the build directory created to run cmake from, it is then
+  copied to the node_modules/qpid-proton/lib directory.
+
+  In this example we also set the global variable PROTON_TOTAL_MEMORY in order to
+  increase the virtual heap available to the emscripten compiled C runtime. It
+  is not really necessary to do this for this application as the default value
+  of 16777216 is fine, it is simply done here to illustrate how to do it.
+-->
+<script type="text/javascript">PROTON_TOTAL_MEMORY = 50000000;</script>
+<script type="text/javascript" src="../../../node_modules/qpid-proton/lib/proton.js"></script>
+
+<script type="text/javascript">
+var message = new proton.Message();
+var messenger = new proton.Messenger();
+
+var sendMessage = function() {
+    var address = document.getElementById("address").value;
+    var subject = document.getElementById("subject").value;
+    var body = document.getElementById("body").value;
+
+console.log("sendMessage");
+console.log("address = " + address);
+console.log("subject = " + subject);
+console.log("body = " + body);
+
+    message.setAddress(address);
+    message.setSubject(subject);
+    message.body = body;
+
+    messenger.put(message);
+};
+
+var errorHandler = function(error) {
+    console.log("Received error " + error);
+};
+
+messenger.on('error', errorHandler);
+messenger.start();
+
+</script>
+
+<style>
+body
+{
+	font: 13px/1.5 Helvetica, Arial, 'Liberation Sans', FreeSans, sans-serif;
+    overflow-x: hidden; /* Hide horizontal scrollbar */
+    background: #dddddd;
+}
+
+label
+{
+    display: block;
+	font-size: 17px;
+}
+
+input, textarea
+{
+	font-size: 13px;
+    margin-bottom: 10px;
+}
+</style>
+
+</head>
+
+<body>
+<div>
+    <label for="address">Address:</label>
+    <input type="text" id="address" size="40"
+           placeholder="amqp://user:password@host:port"
+           name="address" value="amqp://guest:guest@0.0.0.0" />
+</div>
+<div>    
+    <label for="subject">Subject:</label>
+    <input type="text" id="subject" size="40"
+           name="subject" value="Browser Message" />
+</div>
+<div>
+    <label for="body">Message:</label>
+    <textarea id="body" name="body" rows="4" cols="40">Hello From Browser!</textarea>
+</div>
+<div>
+    <input type="button" value="send" onclick="sendMessage()"/>
+</div>
+</body>
+
+</html>
diff --git a/examples/messenger/javascript/send.js b/examples/messenger/javascript/send.js
new file mode 100644
index 0000000..39d40bd
--- /dev/null
+++ b/examples/messenger/javascript/send.js
@@ -0,0 +1,105 @@
+#!/usr/bin/env node
+/*
+ * 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.
+ *
+ */
+
+// Check if the environment is Node.js and if not log an error and exit.
+if (typeof process === 'object' && typeof require === 'function') {
+    // In this example we also set the global variable PROTON_TOTAL_MEMORY in order
+    // to increase the virtual heap available to the emscripten compiled C runtime.
+    // It is not really necessary to do this for this application as the default
+    // value of 16777216 is fine, it is simply done here to illustrate how to do it.
+    PROTON_TOTAL_MEMORY = 50000000;
+    var proton = require("qpid-proton");
+
+    var address = "amqp://0.0.0.0";
+    var subject = "UK.WEATHER";
+    var msgtext = "Hello World!";
+    var tracker = null;
+    var running = true;
+
+    var message = new proton.Message();
+    var messenger = new proton.Messenger();
+
+    // This is an asynchronous send, so we can't simply call messenger.put(message)
+    // at the end of the application as we would with a synchronous/blocking
+    // version, as the application would simply exit without actually sending.
+    // The following callback function (and messenger.setOutgoingWindow())
+    // gives us a means to wait until the consumer has received the message before
+    // exiting. The recv.js example explicitly accepts messages it receives.
+    var pumpData = function() {
+        var status = messenger.status(tracker);
+        if (status != proton.Status.PENDING) {
+            if (running) {
+                messenger.stop();
+                running = false;
+            } 
+        }
+
+        if (messenger.isStopped()) {
+            message.free();
+            messenger.free();
+        }
+    };
+
+    var args = process.argv.slice(2);
+    if (args.length > 0) {
+        if (args[0] === '-h' || args[0] === '--help') {
+            console.log("Usage: node send.js [options] [message]");
+            console.log("Options:");
+            console.log("  -a <addr> The target address [amqp[s]://domain[/name]] (default " + address + ")");
+            console.log("  -s <subject> The message subject (default " + subject + ")");
+            console.log("message A text string to send.");
+            process.exit(0);
+        }
+
+        for (var i = 0; i < args.length; i++) {
+            var arg = args[i];
+            if (arg.charAt(0) === '-') {
+                i++;
+                var val = args[i];
+                if (arg === '-a') {
+                    address = val;
+                } else if (arg === '-s') {
+                    subject = val;
+                }
+            } else {
+                msgtext = arg;
+            }
+        }
+    }
+
+    console.log("Address: " + address);
+    console.log("Subject: " + subject);
+    console.log("Content: " + msgtext);
+
+    messenger.on('error', function(error) {console.log(error);});
+    messenger.on('work', pumpData);
+    messenger.setOutgoingWindow(1024); // So we can track status of send message.
+    messenger.start();
+
+    message.setAddress(address);
+    message.setSubject(subject);
+    message.body = msgtext;
+
+    tracker = messenger.put(message);
+} else {
+    console.error("send.js should be run in Node.js");
+}
+
diff --git a/examples/messenger/javascript/server.js b/examples/messenger/javascript/server.js
new file mode 100644
index 0000000..1a9eabb
--- /dev/null
+++ b/examples/messenger/javascript/server.js
@@ -0,0 +1,81 @@
+#!/usr/bin/env node
+/*
+ * 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.
+ *
+ */
+
+// Simple server for use with client.js illustrating request/response
+
+// Check if the environment is Node.js and if not log an error and exit.
+if (typeof process === 'object' && typeof require === 'function') {
+    var proton = require("qpid-proton");
+
+    var address = "amqp://~0.0.0.0";
+    var message = new proton.Message();
+    var reply   = new proton.Message();
+    var messenger = new proton.Messenger();
+
+    var dispatch = function(request, response) {
+        var subject = request.getSubject();
+        if (subject) {
+            response.setSubject('Re: ' + subject);
+        }
+        response.properties = request.properties
+        console.log("Dispatched " + subject + " " + JSON.stringify(request.properties));
+    };
+
+    var pumpData = function() {
+        while (messenger.incoming()) {
+            var t = messenger.get(message);
+    
+            var replyTo = message.getReplyTo();
+            if (replyTo) {
+                console.log(replyTo);
+                reply.setAddress(replyTo);
+                reply.setCorrelationID(message.getCorrelationID());
+                reply.body = message.body;
+                dispatch(message, reply);
+                messenger.put(reply);
+            }
+    
+            messenger.accept(t);
+        }
+    };
+
+    var args = process.argv.slice(2);
+    if (args.length > 0) {
+        if (args[0] === '-h' || args[0] === '--help') {
+            console.log("Usage: node server.js <addr> (default " + address + ")");
+            process.exit(0);
+        }
+    
+        address = args[0];
+    }
+    
+    messenger.setIncomingWindow(1024);
+    
+    messenger.on('error', function(error) {console.log(error);});
+    messenger.on('work', pumpData);
+    messenger.recv(); // Receive as many messages as messenger can buffer.
+    messenger.start();
+    
+    messenger.subscribe(address);
+} else {
+    console.error("server.js should be run in Node.js");
+}
+
diff --git a/examples/messenger/javascript/spout.js b/examples/messenger/javascript/spout.js
new file mode 100644
index 0000000..16faa8e
--- /dev/null
+++ b/examples/messenger/javascript/spout.js
@@ -0,0 +1,71 @@
+#!/usr/bin/env node
+/*
+ * 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.
+ *
+ */
+
+// Check if the environment is Node.js and if not log an error and exit.
+if (typeof process === 'object' && typeof require === 'function') {
+    var proton = require("qpid-proton");
+
+    console.log("spout not implemented yet");
+    process.exit(0);
+    
+    var address = "amqp://0.0.0.0";
+    var subject = "UK.WEATHER";
+    var msgtext = "Hello World!";
+    var tracker = null;
+    var running = true;
+    
+    var message = new proton.Message();
+    var messenger = new proton.Messenger();
+
+    function pumpData() {
+        var status = messenger.status(tracker);
+        if (status != proton.Status.PENDING) {
+console.log("status = " + status);
+
+            if (running) {
+console.log("stopping");
+                messenger.stop();
+                running = false;
+            } 
+        }
+    
+        if (messenger.isStopped()) {
+console.log("exiting");
+            message.free();
+            messenger.free();
+        }
+    };
+
+    messenger.on('error', function(error) {console.log(error);});
+    messenger.on('work', pumpData);
+    messenger.setOutgoingWindow(1024);
+    messenger.start();
+
+    message.setAddress(address);
+    message.setSubject(subject);
+
+    message.body = msgtext;
+
+    tracker = messenger.put(message);
+} else {
+    console.error("spout.js should be run in Node.js");
+}
+
diff --git a/examples/messenger/javascript/ws2tcp.js b/examples/messenger/javascript/ws2tcp.js
new file mode 100755
index 0000000..abb78f2
--- /dev/null
+++ b/examples/messenger/javascript/ws2tcp.js
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ *
+ */
+
+/**
+ * ws2tcp.js is a simple node.js library that proxies from a WebSocket to a TCP
+ * Socket or vice versa. It has minimal dependencies - the standard node.js net
+ * library and the ws WebSocket library (npm install ws).
+ * <p>
+ * Two fuctions are exported, ws2tcp proxies from a WebSocket to a TCP Socket and
+ * tcp2ws proxies from a TCP Socket to a WebSocket.
+ * @Author Fraser Adams
+ * @file
+ */
+
+var WebSocket = require('ws');
+var net = require('net');
+
+/**
+ * This function is shared by ws2tcp and tcp2ws and takes care of cleaning up
+ * and closing the WebSocket and Socket when things close down or error.
+ * @param sock the TCP Socket instance we're registering cleanup handlers for.
+ * @param ws the WebSocket instance we're registering cleanup handlers for.
+ */
+var registerCleanupCallbacks = function(sock, ws) {
+    var cleanup = function(sock, ws) {
+        sock.removeAllListeners('close');	
+        sock.end();
+        ws.removeAllListeners('close');
+        ws.close();
+    };
+
+    sock.on('close', function() {
+        cleanup(sock, ws);
+    });
+
+    sock.on('error', function (e) {
+        console.log("socket error: " + e.code);
+        cleanup(sock, ws);
+    });
+
+    ws.on('close', function() {
+        cleanup(sock, ws);
+    });
+
+    ws.on('error', function (e) {
+        console.log("websocket error: " + e.code);
+        cleanup(sock, ws);
+    });
+};
+
+/**
+ * This function establishes a proxy that listens on a specified TCP Socket port
+ * and proxies data to a WebSocket on the target host listening on the specified
+ * target port.
+ * @param lport the listen port.
+ * @param thost the target host.
+ * @param tport the target port.
+ * @param subProtocols a string containing a comma separated list of WebSocket sub-protocols.
+ */
+var tcp2ws = function(lport, thost, tport, subProtocols) {
+    var opts = null;
+    if (subProtocols) {
+        // The regex trims the string (removes spaces at the beginning and end,
+        // then splits the string by <any space>,<any space> into an Array.
+        subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
+        opts = {'protocol': subProtocols.toString()};
+    }
+
+    var server = net.createServer(function(sock) {
+        var url = 'ws://' + thost + ':' + tport;
+        var ws = new WebSocket(url, opts);
+        var ready = false;
+        var buffer = [];
+
+        registerCleanupCallbacks(sock, ws);
+
+        sock.on('data', function(data) {
+            if (ready) {
+                ws.send(data);
+            } else {
+                buffer.push(data);
+            }
+        });
+
+        ws.on('open', function () {
+            if (buffer.length > 0) {
+                ws.send(Buffer.concat(buffer));
+            }
+            ready = true;
+            buffer = null;
+        });
+
+        ws.on('message', function(m) {
+            sock.write(m);	
+        });
+    });
+    server.listen(lport);
+};
+
+/**
+ * This function establishes a proxy that listens on a specified WebSocket port
+ * and proxies data to a TCP Socket on the target host listening on the specified
+ * target port.
+ * @param lport the listen port.
+ * @param thost the target host.
+ * @param tport the target port.
+ */
+var ws2tcp = function(lport, thost, tport) {
+    var server = new WebSocket.Server({port: lport});
+    server.on('connection', function(ws) {
+        var sock = net.connect(tport, thost);
+        var ready = false;
+        var buffer = [];
+
+        registerCleanupCallbacks(sock, ws);
+
+        ws.on('message', function(m) {
+            if (ready) {
+                sock.write(m);	
+            } else {
+                buffer.push(m);
+            }
+        });
+
+        sock.on('connect', function() {
+            if (buffer.length > 0) {
+                sock.write(Buffer.concat(buffer));
+            }
+            ready = true;
+            buffer = null;
+        });
+
+        sock.on('data', function(data) {
+            ws.send(data);
+        });
+    });
+    server.on('error', function(e) {
+        console.log("websocket server error: " + e.code);
+    });
+};
+
+// Export the two proxy functions.
+module.exports.ws2tcp = ws2tcp;
+module.exports.tcp2ws = tcp2ws;
+
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 96a0540..7872801 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -261,6 +261,19 @@
   add_subdirectory(bindings)
 endif (SWIG_FOUND)
 
+# Build the JavaScript language binding.
+# This is somewhat different to the other language bindings in that it does not use swig. It uses a C/C++ to
+# JavaScript cross-compiler called emscripten (https://github.com/kripken/emscripten). Emscripten takes C/C++
+# and compiles it into a highly optimisable subset of JavaScript called asm.js (http://asmjs.org/) that can be
+# aggressively optimised and run at near-native speed (usually between 1.5 to 10 times slower than native C/C++).
+option("BUILD_JAVASCRIPT" "Build JavaScript language binding" ON)
+if (BUILD_JAVASCRIPT)
+  find_package(Emscripten)
+  if (EMSCRIPTEN_FOUND)
+    add_subdirectory(bindings/javascript)
+  endif (EMSCRIPTEN_FOUND)
+endif (BUILD_JAVASCRIPT)
+
 add_subdirectory(docs/api)
 add_subdirectory(docs/man)
 add_subdirectory(../tests/tools/apps/c ../tests/tools/apps/c)
diff --git a/proton-c/bindings/javascript/CMakeLists.txt b/proton-c/bindings/javascript/CMakeLists.txt
new file mode 100644
index 0000000..38d039b
--- /dev/null
+++ b/proton-c/bindings/javascript/CMakeLists.txt
@@ -0,0 +1,272 @@
+#
+# 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.
+#
+ 
+# This file allows cross-compiling of proton to JavaScript using emscripten
+# (https://github.com/kripken/emscripten). As it is really a cross-compilation
+# (as opposed to a binding like with swig) the approach is rather different and
+# somewhat replicates the main build in the proton-c/CMakeLists.txt using quite
+# a bit of "copy and paste reuse".
+# TODO refactor this file (and proton-c/CMakeLists.txt) to keep the main
+# compilation and cross-compilation consistent.
+
+message(STATUS "Found emscripten, using that to build JavaScript binding")
+
+# Find and install the node.js packages that we might need. We can assume that
+# node.js itself is installed because Emscripten has a dependency on it.
+find_package(NodePackages)
+
+# Describe the target OS we are building to - Emscripten mimics the Linux platform.
+set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_SYSTEM_VERSION 1)
+set(CMAKE_CROSSCOMPILING TRUE)
+
+# Specify the compiler to use for cross-compilation.
+set(CMAKE_C_COMPILER "${EMCC}")
+
+# Don't do compiler autodetection, since we are cross-compiling.
+include(CMakeForceCompiler)
+CMAKE_FORCE_C_COMPILER("${CMAKE_C_COMPILER}" Clang)
+
+# The Proton default build type is RelWithDebInfo, but for JavaScript the C debug
+# mechanism is irrelevant. If Debug is explicitly set we turn off optimisations
+# and don't run the closure compiler so any error/profiling messages are readable.
+if (CMAKE_BUILD_TYPE STREQUAL "Debug")
+    message(STATUS "JavaScript build type is \"Debug\"")
+else()
+    set (CMAKE_BUILD_TYPE Release)
+    message(STATUS "JavaScript build type is \"Release\"")
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
+    set(EMSCRIPTEN_LINK_OPTIMISATIONS "-O2 --closure 1")
+endif()
+
+# From this point we should be using emscripten compilation tools.
+message(STATUS "emscripten compilation environment:")
+message(STATUS "CMAKE_C_COMPILER: ${CMAKE_C_COMPILER}")
+
+
+# Set this to the proton-c directory, we're cross-compiling code from there.
+set(PN_PATH ${CMAKE_SOURCE_DIR}/proton-c)
+
+
+# TODO the OpenSSL stuff won't work for emscripten by default. It might well be
+# possible to compile it from source using emscripten (that's the standard practice
+# for libraries with emscripten) see https://github.com/kripken/emscripten/wiki/FAQ
+# "Q. How do I link against system libraries like SDL, boost, etc.?"
+# Though it might be more natural to simply use a TLS protected wss:// WebSocket URL.
+#  set(pn_driver_ssl_impl src/ssl/openssl.c)
+#  set(SSL_LIB ${OPENSSL_LIBRARIES})
+set(pn_driver_ssl_impl ${PN_PATH}/src/ssl/ssl_stub.c)
+
+# emscripten is Linux like so use the posix driver.
+set(pn_io_impl ${PN_PATH}/src/posix/io.c)
+set(pn_selector_impl ${PN_PATH}/src/posix/selector.c)
+set(pn_driver_impl ${PN_PATH}/src/posix/driver.c)
+
+
+# Generate encodings.h and protocol.h
+# It may be possible to use the ones generated for the main proton-c build but
+# qpid-proton-core has a dependency on the generated files, so I'm not sure if
+# it'll work without a command that can be run as a dependency. Probably best
+# do it this way when cross-compiling - though more copy'n'paste
+add_custom_command(
+  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/encodings.h
+  COMMAND python ${PN_PATH}/env.py PYTHONPATH=${PN_PATH} python ${PN_PATH}/src/codec/encodings.h.py > ${CMAKE_CURRENT_BINARY_DIR}/encodings.h
+  DEPENDS ${PN_PATH}/src/codec/encodings.h.py
+  )
+
+add_custom_command(
+  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/protocol.h
+  COMMAND python ${PN_PATH}/env.py PYTHONPATH=${PN_PATH} python ${PN_PATH}/src/protocol.h.py > ${CMAKE_CURRENT_BINARY_DIR}/protocol.h
+  DEPENDS ${PN_PATH}/src/protocol.h.py
+  )
+
+set(COMPILE_WARNING_FLAGS "-Werror -Wall -pedantic-errors -Wno-comment -Wno-warn-absolute-paths")
+
+# Explicitly set PLATFORM_DEFINITIONS to Linux ones for emscripten as we don't
+# want to inadvertently use Windows versions if we happen to be cross-compiling
+# from a Windows platform
+set(PLATFORM_DEFINITIONS "USE_CLOCK_GETTIME;USE_UUID_GENERATE;USE_STRERROR_R;USE_ATOLL")
+
+# The following is largely a copy from the the main proton-c/CMakeLists.txt.
+# The main difference is prefixing paths with ${PN_PATH}/ as we can't use a
+# relative path from this CMakeLists.txt.
+
+set(qpid-proton-platform
+  ${pn_io_impl}
+  ${pn_selector_impl}
+  ${pn_driver_impl}
+  ${PN_PATH}/src/platform.c
+  ${pn_driver_ssl_impl}
+  )
+
+set(qpid-proton-core
+  ${PN_PATH}/src/object/object.c
+  ${PN_PATH}/src/object/list.c
+  ${PN_PATH}/src/object/map.c
+  ${PN_PATH}/src/object/string.c
+  ${PN_PATH}/src/object/iterator.c
+  ${PN_PATH}/src/object/record.c
+
+  ${PN_PATH}/src/util.c
+  ${PN_PATH}/src/url.c
+  ${PN_PATH}/src/error.c
+  ${PN_PATH}/src/buffer.c
+  ${PN_PATH}/src/parser.c
+  ${PN_PATH}/src/scanner.c
+  ${PN_PATH}/src/types.c
+
+  ${PN_PATH}/src/framing/framing.c
+
+  ${PN_PATH}/src/codec/codec.c
+  ${PN_PATH}/src/codec/decoder.c
+  ${PN_PATH}/src/codec/encoder.c
+
+  ${PN_PATH}/src/dispatcher/dispatcher.c
+  ${PN_PATH}/src/engine/engine.c
+  ${PN_PATH}/src/events/event.c
+  ${PN_PATH}/src/transport/autodetect.c
+  ${PN_PATH}/src/transport/transport.c
+  ${PN_PATH}/src/message/message.c
+  ${PN_PATH}/src/sasl/sasl.c
+
+  ${PN_PATH}/src/messenger/messenger.c
+  ${PN_PATH}/src/messenger/subscription.c
+  ${PN_PATH}/src/messenger/store.c
+  ${PN_PATH}/src/messenger/transform.c
+  ${PN_PATH}/src/selectable.c
+
+  ${CMAKE_CURRENT_BINARY_DIR}/encodings.h
+  ${CMAKE_CURRENT_BINARY_DIR}/protocol.h
+  )
+
+set_source_files_properties(
+  ${qpid-proton-core}
+  PROPERTIES
+  COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_LANGUAGE_FLAGS}"
+  )
+
+set_source_files_properties(
+  ${qpid-proton-platform}
+  PROPERTIES
+  COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_PLATFORM_FLAGS}"
+  COMPILE_DEFINITIONS "${PLATFORM_DEFINITIONS}"
+  )
+
+# Compile Proton into LLVM bitcode which will be used later in the linking stage
+# of add_executable for compilation into Javascript.
+add_library(
+  qpid-proton-bitcode SHARED
+
+  ${qpid-proton-core}
+  ${qpid-proton-platform}
+  )
+
+set_target_properties(
+  qpid-proton-bitcode
+  PROPERTIES
+  VERSION   "${PN_LIB_SOMAJOR}.${PN_LIB_SOMINOR}"
+  SOVERSION "${PN_LIB_SOMAJOR}"
+  LINK_FLAGS "${CATCH_UNDEFINED}"
+  )
+
+
+# Compile the send-async.c and recv-async.c examples into JavaScript
+add_executable(send-async.js ${PN_PATH}/../examples/messenger/c/send-async.c)
+target_link_libraries(send-async.js qpid-proton-bitcode)
+
+add_executable(recv-async.js ${PN_PATH}/../examples/messenger/c/recv-async.c)
+target_link_libraries(recv-async.js qpid-proton-bitcode)
+
+set_target_properties(
+  send-async.js recv-async.js
+  PROPERTIES
+  COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_PLATFORM_FLAGS}"
+  RUNTIME_OUTPUT_DIRECTORY examples
+  DEPENDS ws
+
+  LINK_FLAGS "-s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" -${EMSCRIPTEN_LINK_OPTIMISATIONS}"
+  )
+
+# Build the main JavaScript library called proton.js
+add_executable(proton.js binding.c)
+target_link_libraries(proton.js qpid-proton-bitcode)
+
+set_target_properties(
+  proton.js
+  PROPERTIES
+  COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_PLATFORM_FLAGS}"
+
+  # The --memory-init-file 0 stops emscripten emitting a separate memory
+  # initialization file, if this was enabled it makes packaging harder as
+  # applications would expect proton.js.mem to be served too. It's even more
+  # fiddly with node.js packages. This behaviour might be reinstated if the
+  # packaging mechanism improves.
+
+  LINK_FLAGS "-s \"EXPORT_NAME='proton'\" -s \"WEBSOCKET_SUBPROTOCOL='AMQPWSB10'\" ${EMSCRIPTEN_LINK_OPTIMISATIONS} --memory-init-file 0 --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-open.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/module.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/error.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/messenger.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/subscription.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/message.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-uuid.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-symbol.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-described.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-array.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-typed-number.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-long.js --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/data-binary.js --post-js ${CMAKE_CURRENT_SOURCE_DIR}/binding-close.js -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=\"[]\" -s EXPORTED_FUNCTIONS=\"['_pn_get_version_major', '_pn_get_version_minor', '_pn_bytes', '_pn_error_text', '_pn_code', '_pn_messenger', '_pn_messenger_name', '_pn_messenger_set_blocking', '_pn_messenger_free', '_pn_messenger_errno', '_pn_messenger_error', '_pn_messenger_get_outgoing_window', '_pn_messenger_set_outgoing_window', '_pn_messenger_get_incoming_window', '_pn_messenger_set_incoming_window', '_pn_messenger_start', '_pn_messenger_stop', '_pn_messenger_stopped', '_pn_messenger_subscribe', '_pn_messenger_put', '_pn_messenger_status', '_pn_messenger_buffered', '_pn_messenger_settle', '_pn_messenger_outgoing_tracker', '_pn_messenger_work', '_pn_messenger_recv', '_pn_messenger_receiving', '_pn_messenger_get', '_pn_messenger_incoming_tracker', '_pn_messenger_incoming_subscription', '_pn_messenger_accept', '_pn_messenger_reject', '_pn_messenger_outgoing', '_pn_messenger_incoming',  '_pn_messenger_route', '_pn_messenger_rewrite', '_pn_messenger_set_passive', '_pn_messenger_selectable', '_pn_subscription_get_context', '_pn_subscription_set_context', '_pn_subscription_address', '_pn_message', '_pn_message_id', '_pn_message_correlation_id', '_pn_message_free', '_pn_message_errno', '_pn_message_error', '_pn_message_clear', '_pn_message_is_inferred', '_pn_message_set_inferred', '_pn_message_is_durable', '_pn_message_set_durable', '_pn_message_get_priority', '_pn_message_set_priority', '_pn_message_get_ttl', '_pn_message_set_ttl', '_pn_message_is_first_acquirer', '_pn_message_set_first_acquirer', '_pn_message_get_delivery_count', '_pn_message_set_delivery_count', '_pn_message_get_user_id', '_pn_message_set_user_id', '_pn_message_get_address', '_pn_message_set_address', '_pn_message_get_subject', '_pn_message_set_subject', '_pn_message_get_reply_to', '_pn_message_set_reply_to', '_pn_message_get_content_type', '_pn_message_set_content_type', '_pn_message_get_content_encoding', '_pn_message_set_content_encoding', '_pn_message_get_expiry_time', '_pn_message_set_expiry_time', '_pn_message_get_creation_time', '_pn_message_set_creation_time', '_pn_message_get_group_id', '_pn_message_set_group_id', '_pn_message_get_group_sequence', '_pn_message_set_group_sequence', '_pn_message_get_reply_to_group_id', '_pn_message_set_reply_to_group_id', '_pn_message_encode', '_pn_message_decode', '_pn_message_instructions', '_pn_message_annotations', '_pn_message_properties', '_pn_message_body', '_pn_data', '_pn_data_free', '_pn_data_error', '_pn_data_errno', '_pn_data_clear', '_pn_data_rewind', '_pn_data_next', '_pn_data_prev', '_pn_data_enter', '_pn_data_exit', '_pn_data_lookup', '_pn_data_narrow', '_pn_data_widen', '_pn_data_type', '_pn_data_encode', '_pn_data_decode', '_pn_data_put_list', '_pn_data_put_map', '_pn_data_put_array', '_pn_data_put_described', '_pn_data_put_null', '_pn_data_put_bool', '_pn_data_put_ubyte', '_pn_data_put_byte', '_pn_data_put_ushort', '_pn_data_put_short', '_pn_data_put_uint', '_pn_data_put_int', '_pn_data_put_char', '_pn_data_put_ulong', '_pn_data_put_long', '_pn_data_put_timestamp', '_pn_data_put_float', '_pn_data_put_double', '_pn_data_put_decimal32', '_pn_data_put_decimal64', '_pn_data_put_decimal128', '_pn_data_put_uuid', '_pn_data_put_binary', '_pn_data_put_string', '_pn_data_put_symbol', '_pn_data_get_list', '_pn_data_get_map', '_pn_data_get_array', '_pn_data_is_array_described', '_pn_data_get_array_type', '_pn_data_is_described', '_pn_data_is_null', '_pn_data_get_bool', '_pn_data_get_ubyte', '_pn_data_get_byte', '_pn_data_get_ushort', '_pn_data_get_short', '_pn_data_get_uint', '_pn_data_get_int', '_pn_data_get_char', '_pn_data_get_ulong', '_pn_data_get_long', '_pn_data_get_timestamp', '_pn_data_get_float', '_pn_data_get_double', '_pn_data_get_decimal32', '_pn_data_get_decimal64', '_pn_data_get_decimal128', '_pn_data_get_uuid', '_pn_data_get_binary', '_pn_data_get_string', '_pn_data_get_symbol', '_pn_data_copy', '_pn_data_format', '_pn_data_dump', '_pn_selectable_readable', '_pn_selectable_capacity', '_pn_selectable_writable', '_pn_selectable_pending', '_pn_selectable_is_terminal', '_pn_selectable_fd', '_pn_selectable_free']\""
+  )
+
+# This command packages up the compiled proton.js into a node.js package called
+# qpid-proton and copies it to the <proton>/node_modules directory. This allows
+# the node.js test and example programs to do proton = require("qpid-proton");
+add_custom_command(
+    TARGET proton.js
+    COMMAND ${CMAKE_COMMAND}
+            -E copy_directory 
+            ${CMAKE_CURRENT_SOURCE_DIR}/qpid-proton 
+            ${PROJECT_SOURCE_DIR}/node_modules/qpid-proton
+    COMMAND ${CMAKE_COMMAND}
+            -E copy
+            ${CMAKE_CURRENT_BINARY_DIR}/proton.js
+            ${PROJECT_SOURCE_DIR}/node_modules/qpid-proton/lib
+   COMMENT "Building qpid-proton package for node.js"
+)
+
+# The cleanall target removes the qpid-proton package from <proton>/node_modules
+add_custom_target(
+    cleanall
+    COMMAND echo "CLEAN NODE MODULES"
+    COMMAND ${CMAKE_COMMAND}
+            -E remove_directory
+            ${PROJECT_SOURCE_DIR}/node_modules/qpid-proton
+)
+
+# If the docs target is specified and the jsdoc3 package for node.js has been
+# installed then build the JavaScript API documentation.
+if (NODE_JSDOC_FOUND)
+    set(JSDOC_EXE ${PROJECT_SOURCE_DIR}/node_modules/.bin/jsdoc)
+
+    message(STATUS "Documentation Enabled. Using ${JSDOC_EXE} to build JavaScript docs")
+    add_custom_target(docs-js COMMAND ${JSDOC_EXE}
+                      -d ${CMAKE_CURRENT_BINARY_DIR}/html
+                      ${CMAKE_CURRENT_SOURCE_DIR}/module.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/error.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/messenger.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/subscription.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/message.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/data.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/data-uuid.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/data-symbol.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/data-described.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/data-array.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/data-typed-number.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/data-long.js
+                      ${CMAKE_CURRENT_SOURCE_DIR}/data-binary.js)
+    add_dependencies(docs docs-js)
+endif (NODE_JSDOC_FOUND)
+
diff --git a/proton-c/bindings/javascript/LICENSE b/proton-c/bindings/javascript/LICENSE
new file mode 100644
index 0000000..6b0b127
--- /dev/null
+++ b/proton-c/bindings/javascript/LICENSE
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+
diff --git a/proton-c/bindings/javascript/README b/proton-c/bindings/javascript/README
new file mode 100644
index 0000000..8bfde56
--- /dev/null
+++ b/proton-c/bindings/javascript/README
@@ -0,0 +1,426 @@
+Qpid Proton JavaScript Language Bindings
+========================================
+
+The code contained herein provides JavaScript language bindings for working
+with the Qpid Proton AMQP 1.0 protocol engine and messenger library.
+
+Important Note - Modern Browser Needed
+======================================
+
+The JavaScript binding requires ArrayBuffer/TypedArray and WebSocket support.
+Both of these are available in most "modern" browser versions. The author has
+only tried running on FireFox and Chrome, though recent Safari, Opera and IE10+
+*should* work too - YMMV. It might be possible to polyfill for older browsers
+but the author hasn't tried this.
+
+Important Note - WebSocket Transport!!!
+=======================================
+
+Before going any further it is really important to realise that the JavaScript
+bindings to Proton are somewhat different to the bindings for other languages
+because of the restrictions of the execution environment. In particular it is
+very important to note that the JavaScript bindings by default use a WebSocket
+transport and not a TCP transport, so whilst it's possible to create Server style
+applications that clients can connect to (e.g. recv.js and send.js) note that:
+
+JavaScript clients cannot *directly* talk to "normal" AMQP applications such as
+qpidd or (by default) the Java Broker because they use a standard TCP transport.
+
+This is a slightly irksome issue, but there's no getting away from it because
+it's a security restriction imposed by the browser environment.
+
+
+At the moment even for Node.js we are limited to using a WebSocket transport, but
+it is on the author's "TODO" list to look at providing a means to use either a
+WebSocket transport or a native TCP transport (via node's net library). It should
+also be possible to use native TCP for Chrome "packaged apps", but again this is
+only on the TODO list so if you want to talk to a "normal" AMQP application you
+must live with the WebSocket constraints.
+
+Option 1. proxy from WebSockets to TCP sockets. The application
+<proton>/examples/messenger/javascript/proxy.js
+is a simple Node.js WebSocket<->TCP Socket proxy, simply doing:
+
+node proxy.js
+
+will stand up a proxy listening by default on WebSocket port 5673 and forwarding
+to TCP port 5672 (this is configurable, for options do: node proxy.js -h)
+
+Rather than using a stand-alone proxy it is possible to have applications stand
+up their own proxy (where lport = listen port, thost = target host and
+tport = target port):
+
+var proxy = require('./ws2tcp.js');
+proxy.ws2tcp(lport, thost, tport);
+
+For talking to the C++ broker unfortunately proxying is currently the only option
+as qpidd does not have a WebSocket transport.
+
+Option 2. The Java Broker's WebSocket transport.
+Recent releases of the Qpid Java Broker provide a native WebSocket transport which
+means that the JavaScript binding can talk to it with no additional requirements.
+It is necessary to configure the Java Broker as the WebSocket transport is not
+enabled by default. In <qpid-work>/config.json in the "ports" array you need to add:
+
+{
+    "authenticationProvider" : "passwordFile",
+    "name" : "AMQP-WS",
+    "port" : "5673",
+    "transports" : [ "WS" ]
+}
+
+This sets the JavaBroker to listen on WebSocket port 5673 similar to the proxy.
+
+
+One gotcha that still bites the author *** DO NOT FORGET *** that you will be
+using ports that you are not used to!! If you are not connecting check that the
+proxy is running and that you are specifying the right ports. I still mess up :-(
+
+WebRTC Transport
+================
+
+A WebRTC Transport is supported by emscripten, though the author has not tried it.
+If you wan to play with this you are very much on your own at the moment YMMV.
+
+This is configured by adding to the LINK_FLAGS in CMakeLists.txt
+-s \"SOCKET_WEBRTC=1\"
+
+  /* WebRTC sockets supports several options on the Module object.
+
+     * Module['host']: true if this peer is hosting, false otherwise
+     * Module['webrtc']['broker']: hostname for the p2p broker that this peer should use
+     * Module['webrtc']['session']: p2p session for that this peer will join, or undefined if this peer is hosting
+     * Module['webrtc']['hostOptions']: options to pass into p2p library if this peer is hosting
+     * Module['webrtc']['onpeer']: function(peer, route), invoked when this peer is ready to connect
+     * Module['webrtc']['onconnect']: function(peer), invoked when a new peer connection is ready
+     * Module['webrtc']['ondisconnect']: function(peer), invoked when an existing connection is closed
+     * Module['webrtc']['onerror']: function(error), invoked when an error occurs
+   */
+
+If you wanted to play with these you'd likely have to tweak the module.js code in
+<proton>/proton-c/bindings/javascript
+
+The emscripten documentation is a bit light on the WebRTC Transport too, though
+
+emscripten/tests/test_sockets.py
+emscripten/tests/sockets/webrtc_host.c
+emscripten/tests/sockets/webrtc_peer.c
+emscripten/tests/sockets/p2p/broker/p2p-broker.js
+emscripten/tests/sockets/p2p/client/p2p-client.js
+
+Look like they provide a starting point.
+Very much TODO......
+
+
+Creating The Bindings
+=====================
+
+To generate the JavaScript bindings we actually cross-compile from proton-c
+
+You will need to have emscripten (https://github.com/kripken/emscripten) installed
+to do the cross-compilation and in addition you will require a few things that
+emscripten itself depends upon.
+
+http://kripken.github.io/emscripten-site/docs/building_from_source/index.html#installing-from-source
+http://kripken.github.io/emscripten-site/docs/building_from_source/toolchain_what_is_needed.html
+provide instructions for installing emscripten and the "fastcomp" LLVM backend.
+This approach lets users use the "bleeding edge" version of emscripten on the
+"incoming" branch (pretty much analogous to building qpid/proton off svn trunk).
+This is the approach that the author of the JavaScript Bindings tends to use.
+
+
+http://kripken.github.io/emscripten-site/docs/getting_started/downloads.html
+provides some fairly easy to follow instructions for getting started on several
+platforms the main dependencies are as follows (on Windows the SDK includes these):
+
+* The Emscripten code, from github (git clone git://github.com/kripken/emscripten.git).
+* LLVM with Clang. Emscripten uses LLVM and Clang, but at the moment the JavaScript
+  back-end for LLVM is off on a branch so you can't use a stock LLVM/Clang.
+  http://kripken.github.io/emscripten-site/docs/building_from_source/LLVM-Backend.html
+  http://kripken.github.io/emscripten-site/docs/building_from_source/building_fastcomp_manually_from_source.html#building-fastcomp-from-source
+  has lots of explanation and some easy to follow instructions for downloading
+  and building fastcomp
+* Node.js (0.8 or above; 0.10.17 or above to run websocket-using servers in node)
+* Python 2.7.3
+* Java is required in order to use the Closure Compiler to minify the code.
+  
+
+If you haven't run Emscripten before it's a good idea to have a play with the
+tutorial here:
+http://kripken.github.io/emscripten-site/docs/getting_started/Tutorial.html
+
+
+
+when you are all set up with emscripten and have got the basic tests in the
+tutorial running building Proton should be simple, simply go to the Proton root
+directory and follow the main instructions in the README there, in precis (from
+the root directory) it's:
+
+  mkdir build
+  cd build
+  cmake ..
+  make
+
+and you should be all set, to test it's all working do (from the build directory):
+  cd proton-c/bindings/javascript/examples
+
+  node recv-async.js
+
+in one window and
+
+  node send-async.js
+
+in another.
+
+These examples are actually JavaScript applications that have been directly
+compiled from recv-async.c and send-async.c in <proton>/examples/messenger/c
+if you'd prefer to write applications in C and compile them to JavaScript that
+is a perfectly valid approach and these examples provide a reasonable starting
+point for doing so.
+
+Documentation
+=============
+
+When you've successfully got a working build do:
+
+  make docs
+
+Which will make all of the proton documentation including the JavaScript docs.
+If successful the JSDoc generated documentation should be found here:
+
+<proton>/build/proton-c/bindings/javascript/html/index.html
+
+
+Using "native" JavaScript
+=========================
+
+The examples in <proton>/examples/messenger/javascript are the best starting point.
+
+In practice the examples follow a fairly similar pattern to the Python bindings
+the most important thing to bear in mind though is that JavaScript is completely
+asynchronous/non-blocking, which can catch the unwary.
+
+An application follows the following (rough) steps:
+
+1. (optional) Set the heap size.
+It's important to realise that most of the library code is compiled C code and
+the runtime uses a "virtual heap" to support the underlying malloc/free. This is
+implemented internally as an ArrayBuffer with a default size of 16777216.
+
+To allocate a larger heap an application must set the PROTON_TOTAL_MEMORY global.
+In Node.js this would look like (see send.js):
+PROTON_TOTAL_MEMORY = 50000000; // Note no var - it needs to be global.
+
+In a browser it would look like (see send.html):
+<script type="text/javascript">PROTON_TOTAL_MEMORY = 50000000;</script>
+
+2. Load the library and create a message and messenger.
+In Node.js this would look like (see send.js):
+var proton = require("qpid-proton");
+var message = new proton.Message();
+var messenger = new proton.Messenger();
+
+In a browser it would look like (see send.html):
+<script type="text/javascript" src="../../../node_modules/qpid-proton/lib/proton.js"></script>
+
+<script type="text/javascript">
+var message = new proton.Message();
+var messenger = new proton.Messenger();
+....
+
+3. Set up event handlers as necessary.
+
+messenger.on('error', <error callback>);
+messenger.on('work', <work callback>);
+messenger.on('subscription', <subscription callback>);
+
+
+The work callback is triggered on WebSocket events, so in general you would use
+this to send and receive messages, for example in recv.js we have:
+
+var pumpData = function() {
+    while (messenger.incoming()) {
+        var t = messenger.get(message);
+
+        console.log("Address: " + message.getAddress());
+        console.log("Subject: " + message.getSubject());
+
+        // body is the body as a native JavaScript Object, useful for most real cases.
+        //console.log("Content: " + message.body);
+
+        // data is the body as a proton.Data Object, used in this case because
+        // format() returns exactly the same representation as recv.c
+        console.log("Content: " + message.data.format());
+
+        messenger.accept(t);
+    }
+};
+
+messenger.on('work', pumpData);
+
+
+The subscription callback is triggered when the address provided in a call to
+messenger.subscribe(<address>);
+
+Gets resolved. An example of its usage can be found in qpid-config.js which is
+a fully functioning and complete port of the python qpid-config tool. It also
+illustrates how to do asynchronous request/response based applications.
+
+Aside from the asynchronous aspects the rest of the API is essentially the same
+as the Python binding aside from minor things such as camel casing method names etc.
+
+Serialisation/Deserialisation, Types etc.
+=========================================
+
+The JavaScript binding tries to be as simple, intuitive and natural as possible
+so when sending a message all native JavaScript types including Object literals
+and Arrays are transparently supported, for example.
+
+var message = new proton.Message();
+message.setAddress('amqp://localhost');
+message.setSubject('UK.NEWS');
+message.body = ['Rod', 'Jane', 'Freddy', {cat: true, donkey: 'hee haw'}];
+
+
+The main thing to bear in mind is that (particularly for sending messages) we
+may need to use "adapters" to make sure values are correctly interpreted and
+encoded to the correct type in the AMQP type system. This is especially important
+when interoperating with a peer written in a strongly typed language (C/C++/Java).
+
+Some examples of available types follow:
+
+// UUID
+message.body = new proton.Data.Uuid();
+
+// AMQP Symbol
+message.body = new proton.Data.Symbol("My Symbol");
+
+// Binary data (created from a gibberish String in this case).
+message.body = new proton.Data.Binary("Monkey Bathпогромзхцвбнм");
+
+// Binary data (Get a Uint8Array view of the data and directly access that).
+message.body = new proton.Data.Binary(4);
+var buffer = message.body.getBuffer();
+buffer[0] = 65;
+buffer[1] = 77;
+buffer[2] = 81;
+buffer[3] = 80;
+
+// Binary Data (Created from an Array, you can use an ArrayBuffer/TypedArray too).
+message.body = new proton.Data.Binary([65, 77, 81, 80]);
+
+
+Note that the implementation of proton.Data.Binary tries to minimise copying so
+it accesses the internal emscripten heap *directly* this requires memory management
+which is mostly handled transparently, but users need to be aware that the
+underlying memory is "owned" by the Message Object, so if Binary data needs to
+be maintained after the next call to messenger.get(message); it must be
+*explicitly* copied. For more detail do "make docs" and see:
+<proton>/build/proton-c/bindings/javascript/html/proton.Data.Binary.html
+
+
+// AMQP Described (value, descriptor)
+message.body = new proton.Data.Described('persian, 'com.cheezburger.icanhas');
+
+// AMQP Timestamp maps to native JavaScript Date.
+message.body = new Date();
+
+// Various AMQP Array examples.
+message.body = new proton.Data.Array('INT', [1, 3, 5, 7], "odd numbers");
+message.body = new proton.Data.Array('UINT', [1, 3, 5, 7], "odd");
+message.body = new proton.Data.Array('ULONG', [1, 3, 5, 7], "odd");
+message.body = new proton.Data.Array('FLOAT', [1, 3, 5, 7], "odd");
+message.body = new proton.Data.Array('STRING', ["1", "3", "5", "7"], "odd");
+
+// A JavaScript TypedArray will map directly to and from an AMQP Array of the
+// appropriate type (Internally sets a descriptor of 'TypedArray').
+message.body = new Uint8Array([1, 3, 5, 7]);
+
+// UUID Array
+message.body = new proton.Data.Array('UUID', [new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid()], "unique");
+
+// Null
+message.body = null;
+
+// Boolean
+message.body = true;
+
+// Native JavaScript Array maps to an AMQP List
+message.body = ['Rod', 'Jane', 'Freddy'];
+
+// Native JavaScript Object maps to an AMQP Map
+message.body = ['Rod', 'Jane', 'Freddy', {cat: true, donkey: 'hee haw'}];
+
+// JavaScript only has a "number" type so the binding provides "decorator"
+// methods added to the JavaScript Number class. To access this from number
+// primitives it is necessary to either use braces or use a "double dot" so that
+// the interpreter can disambiguate from a simple decimal point. The binding will
+// attempt to use the correct type such that message.body = 2147483647; would be
+// sent as an AMQP integer, but because of the way JavaScript coerces integers
+// message.body = 2147483647.0; would also be sent as an AMQP integer because
+// 2147483647.0 gets transparently conveted to 2147483647 by the interpreter, so
+// to explicitly send this as an AMQP float we'd need to do:
+// message.body = 2147483647.0.float();
+
+// Some more number examples:
+message.body = 66..char();  // char - note double dot. (66).char(); works too.
+message.body = 2147483647;  // int
+message.body = -2147483649; // long
+message.body = 12147483649; // long
+message.body = (12147483649).long(); // long
+message.body = (17223372036854778000).ulong(); // ulong
+message.body = (121474.836490).float(); // float
+message.body = 12147483649.0.float(); // float
+message.body = (4294967296).uint(); // uint
+message.body = (255).ubyte(); // ubyte
+
+Note too that floats are subject to a loss of precision
+
+
+Fortunately most of these quirks only affect serialisation.when the binding
+receives a message it will attempt to decode it into the most "natural" native
+JavaScript type.
+
+
+One additional decoding "quirk" can be caused by C++ qpid::messaging clients. It
+is unfortunately quite common for C++ clients to incorrectly encode Strings as
+AMQP Binary by neglecting to provide an encoding. The QMF Management Agent is one
+such culprit. This is a bit of a pain, especially because of proton.Data.Binary
+memory management quirks and having to remember to explicitly copy the data
+on each call to messenger.get(message); In order to cater for this an overloaded
+messenger.get(message, true); has been provided. Setting the second parameter to
+true forces any received Binary payloads to be decoded as Strings. If you know
+that producers might behave in this way and you are not expecting any "real"
+Binary data from the producer this convenience mechanism results in nice clean
+JavaScript Objects being received and is extremely useful for things like QMF.
+
+JSON
+====
+
+As well as allowing native JavaScript Objects and Arrays to be transparently
+serialised and deserialised via the AMQP type system it is also possible to
+serialise/deserialise as JSON.
+
+message.setAddress('amqp://localhost');
+message.setContentType('application/json');
+message.body = {array: [1, 2, 3, 4], object: {name: "John Smith", age: 65}};
+
+On the wire the above will be encoded as an opaque binary in an AMQP data section
+but will be deserialised into a JavaScript Object in exactly the same was as the
+previous examples that use the AMQP type system.
+
+SUPPORT
+=======
+
+To report bugs in the bindings, or to request an enhancement, please file
+a tracker request:
+
+    https://issues.apache.org/jira/browse/PROTON
+
+The main support channel is the qpid-users mailing list, see:
+
+    http://qpid.apache.org/discussion.html#mailing-lists
+
+You can also directly interact with the development team and other users
+in the #qpid channel on irc.freenode.net.
+
diff --git a/proton-c/bindings/javascript/TODO b/proton-c/bindings/javascript/TODO
new file mode 100644
index 0000000..092ee2e
--- /dev/null
+++ b/proton-c/bindings/javascript/TODO
@@ -0,0 +1,49 @@
+Qpid Proton JavaScript Language Bindings TODO List
+==================================================
+
+Network code is currently limited to a WebSocket transport, including for Node.js
+It would be good to allow a configurable transport so that Node.js and Chrome
+packaged apps could use native TCP sockets.
+
+The JavaScript binding is pure JavaScript, that has been  trans-compiled from C
+to JavaScript using emscripten. This allows the same code to be used in a browser
+and Node.js, but it potentially has a performance penalty in Node.js. An alternative
+for Node.js might be to build a SWIG binding (recent versions of SWIG support
+JavaScript). This should be viewed as a complementary not competing approach as
+it would only work for environments like Node.js and definitely *not* browser
+environments which clearly require pure JavaScript.
+
+Optimisation are enabled for compiling and linking but there hasn't been any
+profiling done yet. The binding code *shouldn't* be the bottleneck but it's
+always possible that I messed up.
+
+Error handling is nowhere near as good as it should be, though this is mostly
+because Messenger itself is a bit lacking on the error handling/recovery front.
+
+Although described as "Proton" this is currently a JavaScript binding for Messenger
+and associated Message & Data classes. There has been some talk on the user list
+of an alternative reactive API based on proton Engine. This might ultimately be
+a better fit for JavaScript but it is very much in its infancy and I haven't
+really looked at it yet.
+
+proton-j seems to use hawt-dispatch, which is modelled after Grand Central
+Dispatch so I need to work out what it's using it do do and whether there are
+parallels in proton-c
+
+Although the WebSocket transport uses the sub-protocol 'AMQPWSB10' as specified
+in http://docs.oasis-open.org/amqp-bindmap/amqp-wsb/v1.0/amqp-wsb-v1.0.html
+section 2.1 is is not technically compliant with the spec. as the AMQP data is
+created by the proton-c code, which produces a data-stream for the TCP transport
+whereas the WebSocket spec. seems to want to make use of the fact that WebSocket
+is a frame based transport (whereas TCP is not). This is quite hard to resolve
+as the binding simply sends the contents of the octet buffer created by proton
+over the transport and thus to make this binding compliant with the spec. would
+require a change to the underlying proton-c code! It is possible that this may be
+done in future as any SCTP would require the ability to push AMQP frames too.
+In the mean time fortunately the Java Broker WebSocket transport is actually
+tolerant of this off-spec. behaviour. My personal view is that both approaches
+should be valid and in particular using the standard TCP framing means that it
+is straightforward to create WebSocket<->TCP proxies, which is useful given that
+only the Java Broker currently has a native WebSocket transport.
+
+
diff --git a/proton-c/bindings/javascript/binding-close.js b/proton-c/bindings/javascript/binding-close.js
new file mode 100644
index 0000000..07b68c2
--- /dev/null
+++ b/proton-c/bindings/javascript/binding-close.js
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ *
+ */
+
+/**
+ * These values are essentially constants sitting in the proton namespace
+ * that is to say they will be exported via:
+ * proton.VERSION_MAJOR
+ * proton.VERSION_MINOR
+ * We have to set them after pn_get_version_major/pn_get_version_minor have been
+ * defined so we must do it here in binding-close.js as it's a --post-js block.
+ */
+Module['VERSION_MAJOR'] = _pn_get_version_major();
+Module['VERSION_MINOR'] = _pn_get_version_minor();
+
+})(); // End of self calling lambda used to wrap library.
+
diff --git a/proton-c/bindings/javascript/binding-open.js b/proton-c/bindings/javascript/binding-open.js
new file mode 100644
index 0000000..40e1b12
--- /dev/null
+++ b/proton-c/bindings/javascript/binding-open.js
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ *
+ */
+
+(function() { // Start of self-calling lambda used to avoid polluting global namespace.
diff --git a/proton-c/bindings/javascript/binding.c b/proton-c/bindings/javascript/binding.c
new file mode 100644
index 0000000..ecc65dc
--- /dev/null
+++ b/proton-c/bindings/javascript/binding.c
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+ * This file is largely just a stub, we're actually creating a JavaScript library
+ * rather than an executable so most of the  work is done at the link stage.
+ * We do however need to link the libqpid-proton-bitcode.so with *something* and
+ * this is it. This file also provides a way to pass any global variable or
+ * #defined values to the JavaScript binding by providing wrapper functions.
+ */
+#include <stdio.h>
+#include <proton/version.h>
+
+// To access #define values in JavaScript we need to wrap them in a function.
+int pn_get_version_major() {return PN_VERSION_MAJOR;}
+int pn_get_version_minor() {return PN_VERSION_MINOR;}
+
diff --git a/proton-c/bindings/javascript/data-array.js b/proton-c/bindings/javascript/data-array.js
new file mode 100644
index 0000000..6f9776d
--- /dev/null
+++ b/proton-c/bindings/javascript/data-array.js
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                             proton.Data.Array                             */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * TODO make this behave more like a native JavaScript Array: http://www.bennadel.com/blog/2292-extending-javascript-arrays-while-keeping-native-bracket-notation-functionality.htm
+ * Create a proton.Data.Array.
+ * @classdesc
+ * This class represents an AMQP Array.
+ * @constructor proton.Data.Array
+ * @param {string|number} type the type of the Number either as a string or number.
+ *        Stored internally as a string corresponding to one of the TypeNames.       
+ * @param {Array|TypedArray} elements the Native JavaScript Array or TypedArray that we wish to serialise.
+ * @param {object} descriptor an optional object describing the type.
+ */
+Data['Array'] = function(type, elements, descriptor) { // Data.Array Constructor.
+    // This block caters for an empty Array or a Described empty Array.
+    if (arguments.length < 2) {
+        descriptor = type;
+        type = 'NULL';
+        elements = [];
+    }
+
+    this['type']  = (typeof type === 'number') ? Data['TypeNames'][type] : type;
+    this['elements'] = elements;
+    this['descriptor'] = descriptor;
+};
+
+/**
+ * @method toString
+ * @memberof! proton.Data.Array#
+ * @returns {string} the String form of a {@link proton.Data.Array}.
+ */
+Data['Array'].prototype.toString = function() {
+    var descriptor = (this['descriptor'] == null) ? '' : ':' + this['descriptor'];
+    return this['type'] + 'Array' + descriptor + '[' + this['elements'] + ']';
+};
+
+/**
+ * @method valueOf
+ * @memberof! proton.Data.Array#
+ * @returns {Array} the elements of the {@link proton.Data.Array}.
+ */
+Data['Array'].prototype.valueOf = function() {
+    return this['elements'];
+};
+
+/**
+ * Compare two instances of proton.Data.Array for equality. N.B. this method
+ * compares the value of every Array element so its performance is O(n).
+ * @method equals
+ * @memberof! proton.Data.Array#
+ * @param {proton.Data.Array} rhs the instance we wish to compare this instance with.
+ * @returns {boolean} true iff the two compared instances are equal.
+ */
+Data['Array'].prototype['equals'] = function(rhs) {
+    if (rhs instanceof Data['Array'] &&
+        // Check the string value of the descriptors.
+        (('' + this['descriptor']) === ('' + rhs['descriptor'])) &&
+        (this['type'] === rhs['type'])) {
+        var elements = this['elements'];
+        var relements = rhs['elements'];
+        var length = elements.length;
+        if (length === relements.length) {
+            for (var i = 0; i < length; i++) {
+                if (elements[i].valueOf() !== relements[i].valueOf()) {
+                    return false;
+                }
+            }
+            return true;
+        } else {
+            return false;
+        }
+    } else {
+        return false;
+    }
+};
+
diff --git a/proton-c/bindings/javascript/data-binary.js b/proton-c/bindings/javascript/data-binary.js
new file mode 100644
index 0000000..27bac59
--- /dev/null
+++ b/proton-c/bindings/javascript/data-binary.js
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                             proton.Data.Binary                            */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Create a proton.Data.Binary. This constructor takes one or two parameters.
+ * The first parameter may serve different purposes depending on its type;
+ * If value is a number then it represents the size of the Binary data buffer,
+ * if it is a string then we copy the string to the buffer, if it is an Array
+ * or a TypedArray then we copy the data to the buffer. The optional second
+ * parameter is a pointer to the data in an internal data store. If start is
+ * not specified then the number of bytes specified in the first parameter
+ * will be allocated in the internal data store and start will point to the
+ * start of that block of data.
+ * @classdesc
+ * This class represents an AMQP Binary type. This class allows us to create and
+ * use raw binary data and map it efficiently between JavaScript client code and
+ * the underlying implementation, where all data is managed on a "virtual heap".
+ * <p>
+ * Client applications should generally not have to care about memory management
+ * as, for most common use cases, client applications would "transfer ownership"
+ * to a "container" which would then "own" the underlying data and free the data
+ * held by the {@link proton.Data.Binary}.
+ * <p>
+ * As an example one common use-case would be where client application creates a
+ * {@link proton.Data.Binary} specifying the required size. It would usually then
+ * call getBuffer() to access the underlying Uint8Array. At this point the client
+ * "owns" the data and so would have to call free() if it did nothing more with
+ * the Binary, however when {@link proton.Data.putBINARY} is called the ownership
+ * of the raw data on the virtual heap transfers from the Binary to the Data and
+ * the client no longer needs to call free() itself. In this case the putBINARY()
+ * call transfers ownership and can then safely call free() on the Binary.
+ * <p>
+ * Conversely a common use-case when receiving data is where a Binary may be
+ * created by {@link proton.Data#getBINARY}. In this case the Binary is simply a
+ * "view" onto the bytes owned by the Data instance. A client application can
+ * safely access the bytes from the view, but if it wishes to use the bytes beyond
+ * the scope of the Data instance (e.g. after the next {@link proton.Messenger#get}
+ * call then the client must explicitly *copy* the bytes into a new buffer, for
+ * example via copyBuffer().
+ * <p>
+ * Most of the {@link proton.Data} methods that take {@link proton.Data.Binary}
+ * as a parameter "consume" the underlying data and take responsibility for
+ * freeing it from the heap e.g. {@link proton.Data#putBINARY}, {@link proton.Data#decode}.
+ * For the methods that return a {@link proton.Data.Binary} the call to
+ * {@link proton.Data#getBINARY}, which is the most common case, returns a Binary
+ * that has a "view" of the underlying data that is actually owned by the Data
+ * instance and thus doesn't need to be explicitly freed on the Binary. The call
+ * to {@link proton.Data#encode} however returns a Binary that represents a *copy*
+ * of the underlying data, in this case (like a client calling new proton.Data.Binary)
+ * the client takes responsibility for freeing the data, unless of course it is
+ * subsequently passed to a method that will consume the data (putBINARY/decode).
+ * @constructor proton.Data.Binary
+ * @param {(number|string|Array|TypedArray)} value If value is a number then it 
+ *        represents the size of the Binary data buffer, if it is a string then
+ *        we copy the string to the buffer, if it is an Array or a TypedArray
+ *        then we copy the data to the buffer. N.B. although convenient do bear
+ *        in mind that using a mechanism other than constructing with a simple
+ *        size will result in some form of additional data copy.
+ * @param {number} start an optional pointer to the start of the Binary data buffer.
+ */
+Data['Binary'] = function(value, start) { // Data.Binary Constructor.
+    /**
+     * If the start pointer is specified then the underlying binary data is owned
+     * by another object, so we set the call to free to be a null function. If
+     * the start pointer is not passed then we allocate storage of the specified
+     * size on the emscripten heap and set the call to free to free the data from
+     * the emscripten heap.
+     */
+    var size = value;
+    if (start) {
+        this['free'] = function() {};
+    } else { // Create Binary from Array, ArrayBuffer or TypedArray.
+        var hasArrayBuffer = (typeof ArrayBuffer === 'function');
+        if (Data.isArray(value) ||
+            (hasArrayBuffer && value instanceof ArrayBuffer) || 
+            (value.buffer && hasArrayBuffer && value.buffer instanceof ArrayBuffer)) {
+            value = new Uint8Array(value);
+            size = value.length;
+            start = _malloc(size); // Allocate storage from emscripten heap.
+            Module['HEAPU8'].set(value, start); // Copy the data to the emscripten heap.
+        } else if (Data.isString(value)) { // Create Binary from native string
+            value = unescape(encodeURIComponent(value)); // Create a C-like UTF representation.
+            size = value.length;
+            start = _malloc(size); // Allocate storage from emscripten heap.
+            for (var i = 0; i < size; i++) {
+                setValue(start + i, value.charCodeAt(i), 'i8', 1);
+            }
+        } else { // Create unpopulated Binary of specified size.
+            // If the type is not a number by this point then an unrecognised data
+            // type has been passed so we create a zero length Binary.
+            size = Data.isNumber(size) ? size : 0;
+            start = _malloc(size); // Allocate storage from emscripten heap.
+        }
+        this['free'] = function() {
+            _free(this.start);
+            this.size = 0;
+            this.start = 0;
+            // Set free to a null function to prevent possibility of a "double free".
+            this['free'] = function() {};
+        };
+    }
+
+    this.size = size;
+    this.start = start;
+};
+
+/**
+ * Get a Uint8Array view of the data. N.B. this is just a *view* of the data,
+ * which will go out of scope on the next call to {@link proton.Messenger.get}. If
+ * a client wants to retain the data then copy should be used to explicitly
+ * create a copy of the data which the client then owns to do with as it wishes.
+ * @method getBuffer
+ * @returns {Uint8Array} a new Uint8Array view of the data.
+ * @memberof! proton.Data.Binary#
+ */
+Data['Binary'].prototype['getBuffer'] = function() {
+    return new Uint8Array(HEAPU8.buffer, this.start, this.size);
+};
+
+/**
+ * Explicitly create a *copy* of the Binary, copying the underlying binary data too.
+ * @method copy
+ * @param {number} offset an optional offset into the underlying buffer from
+ *        where we want to copy the data, default is zero.
+ * @param {number} n an optional number of bytes to copy, default is this.size - offset.
+ * @returns {proton.Data.Binary} a new {@link proton.Data.Binary} created by copying the underlying binary data.
+ * @memberof! proton.Data.Binary#
+ */
+Data['Binary'].prototype['copy'] = function(offset, n) {
+    offset = offset | 0;
+    n = n ? n : (this.size - offset);
+
+    if (offset >= this.size) {
+        offset = 0;
+        n = 0;
+    } else if ((offset + n) > this.size) {
+        n = this.size - offset; // Clamp length
+    }
+
+    var start = _malloc(n); // Allocate storage from emscripten heap.
+    _memcpy(start, this.start + offset, n); // Copy the raw data to new buffer.
+
+    return new Data['Binary'](n, start);
+};
+
+/**
+ * Converts the {@link proton.Data.Binary} to a string. This is clearly most
+ * useful when the binary data is actually a binary representation of a string
+ * such as a C style ASCII string.
+ * @method toString
+ * @memberof! proton.Data.Binary#
+ * @returns {string} the String form of a {@link proton.Data.Binary}.
+ */
+Data['Binary'].prototype.toString = Data['Binary'].prototype.valueOf = function() {
+    // Create a native JavaScript String from the start/size information.
+    return Pointer_stringify(this.start, this.size);
+};
+
diff --git a/proton-c/bindings/javascript/data-described.js b/proton-c/bindings/javascript/data-described.js
new file mode 100644
index 0000000..e1f9d84
--- /dev/null
+++ b/proton-c/bindings/javascript/data-described.js
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                             proton.Data.Described                         */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Create a proton.Data.Described.
+ * @classdesc
+ * This class represents an AMQP Described.
+ * @constructor proton.Data.Described
+ * @param {object} value the value of the described type.
+ * @param {string} descriptor an optional string describing the type.
+ * @property {object} value the actual value of the described type.
+ * @property {string} descriptor a string describing the type.
+ */
+Data['Described'] = function(value, descriptor) { // Data.Described Constructor.
+    this['value'] = value;
+    this['descriptor'] = descriptor;
+};
+
+/**
+ * @method toString
+ * @memberof! proton.Data.Described#
+ * @returns {string} the String form of a {@link proton.Data.Described}.
+ */
+Data['Described'].prototype.toString = function() {
+    return 'Described(' + this['value'] + ', ' + this['descriptor'] + ')';
+};
+
+/**
+ * @method valueOf
+ * @memberof! proton.Data.Described#
+ * @returns {object} the value of the {@link proton.Data.Described}.
+ */
+Data['Described'].prototype.valueOf = function() {
+    return this['value'];
+};
+
+/**
+ * Compare two instances of proton.Data.Described for equality.
+ * @method equals
+ * @memberof! proton.Data.Described#
+ * @param {proton.Data.Described} rhs the instance we wish to compare this instance with.
+ * @returns {boolean} true iff the two compared instances are equal.
+ */
+Data['Described'].prototype['equals'] = function(rhs) {
+    if (rhs instanceof Data['Described']) {
+        return ((this['descriptor'] === rhs['descriptor']) && (this['value'] === rhs['value']));
+    } else {
+        return false;
+    }
+};
+
diff --git a/proton-c/bindings/javascript/data-long.js b/proton-c/bindings/javascript/data-long.js
new file mode 100644
index 0000000..38fb6c8
--- /dev/null
+++ b/proton-c/bindings/javascript/data-long.js
@@ -0,0 +1,191 @@
+/*
+ * 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.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                             proton.Data.Long                              */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Create a proton.Data.Long.
+ * @classdesc
+ * This class represents a 64 bit Integer value. It is used primarily to pass and
+ * return 64 bit Integer values to and from the emscripten compiled proton-c library.
+ * This class is needed because JavaScript cannot natively represent 64 bit
+ * Integers with sufficient accuracy.
+ * @constructor proton.Data.Long
+ * @param {number} low the least significant word.
+ * @param {number} high the most significant word.
+ */
+// Use dot notation as it is a "protected" inner class not exported from the closure.
+Data.Long = function(low, high) { // Data.Long Constructor.
+    this.low  = low  | 0;  // force into 32 signed bits.
+    this.high = high | 0;  // force into 32 signed bits.
+};
+
+// proton.Data.Long constants.
+Data.Long.TWO_PWR_16_DBL_ = 1 << 16;
+Data.Long.TWO_PWR_32_DBL_ = Data.Long.TWO_PWR_16_DBL_ * Data.Long.TWO_PWR_16_DBL_;
+Data.Long.TWO_PWR_64_DBL_ = Data.Long.TWO_PWR_32_DBL_ * Data.Long.TWO_PWR_32_DBL_;
+Data.Long.TWO_PWR_63_DBL_ = Data.Long.TWO_PWR_64_DBL_ / 2;
+Data.Long.MAX_VALUE = new Data.Long(0xFFFFFFFF | 0, 0x7FFFFFFF | 0);
+Data.Long.MIN_VALUE = new Data.Long(0, 0x80000000 | 0);
+Data.Long.ZERO = new Data.Long(0, 0);
+Data.Long.ONE  = new Data.Long(1, 0);
+
+/**
+ * @method fromNumber
+ * @memberof! proton.Data.Long#
+ * @returns {proton.Data.Long} an instance of {@link proton.Data.Long} created
+ *          using a native JavaScript number.
+ */
+Data.Long.fromNumber = function(value) {
+    if (isNaN(value) || !isFinite(value)) {
+        return Data.Long.ZERO;
+    } else if (value <= -Data.Long.TWO_PWR_63_DBL_) {
+        return Data.Long.MIN_VALUE;
+    } else if (value + 1 >= Data.Long.TWO_PWR_63_DBL_) {
+        return Data.Long.MAX_VALUE;
+    } else if (value < 0) {
+        return Data.Long.fromNumber(-value).negate();
+    } else {
+      return new Data.Long(
+          (value % Data.Long.TWO_PWR_32_DBL_) | 0,
+          (value / Data.Long.TWO_PWR_32_DBL_) | 0);
+    }
+};
+
+/**
+ * Return the twos complement of this instance.
+ * @method negate
+ * @memberof! proton.Data.Long#
+ * @returns {proton.Data.Long} the twos complement of this instance.
+ */
+Data.Long.prototype.negate = function() {
+    if (this.equals(Data.Long.MIN_VALUE)) {
+        return Data.Long.MIN_VALUE;
+    } else {
+        return this.not().add(Data.Long.ONE);
+    }
+};
+
+/**
+ * Add two instances of {@link proton.Data.Long}.
+ * @method add
+ * @memberof! proton.Data.Long#
+ * @param {proton.Data.Long} rhs the instance we wish to add to this instance.
+ * @returns {proton.Data.Long} the sum of this value and the rhs.
+ */
+Data.Long.prototype.add = function(rhs) {
+    // Divide each number into 4 chunks of 16 bits, and then sum the chunks.
+
+    var a48 = this.high >>> 16;
+    var a32 = this.high & 0xFFFF;
+    var a16 = this.low >>> 16;
+    var a00 = this.low & 0xFFFF;
+
+    var b48 = rhs.high >>> 16;
+    var b32 = rhs.high & 0xFFFF;
+    var b16 = rhs.low >>> 16;
+    var b00 = rhs.low & 0xFFFF;
+
+    var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
+    c00 += a00 + b00;
+    c16 += c00 >>> 16;
+    c00 &= 0xFFFF;
+    c16 += a16 + b16;
+    c32 += c16 >>> 16;
+    c16 &= 0xFFFF;
+    c32 += a32 + b32;
+    c48 += c32 >>> 16;
+    c32 &= 0xFFFF;
+    c48 += a48 + b48;
+    c48 &= 0xFFFF;
+    return new Data.Long((c16 << 16) | c00, (c48 << 16) | c32);
+};
+
+/**
+ * Return the complement of this instance.
+ * @method not
+ * @memberof! proton.Data.Long#
+ * @returns {proton.Data.Long} the complement of this instance.
+ */
+Data.Long.prototype.not = function() {
+    return new Data.Long(~this.low, ~this.high);
+};
+
+/**
+ * Compare two instances of {@link proton.Data.Long} for equality.
+ * @method equals
+ * @memberof! proton.Data.Long#
+ * @param {proton.Data.Long} rhs the instance we wish to compare this instance with.
+ * @returns {boolean} true iff the two compared instances are equal.
+ */
+Data.Long.prototype.equals = function(other) {
+    return (this.high == other.high) && (this.low == other.low);
+};
+
+/**
+ * @method getHighBits
+ * @memberof! proton.Data.Long#
+ * @returns {number} the most significant word of a {@link proton.Data.Long}.
+ */
+Data.Long.prototype.getHighBits = function() {
+    return this.high;
+};
+
+/**
+ * @method getLowBits
+ * @memberof! proton.Data.Long#
+ * @returns {number} the least significant word of a {@link proton.Data.Long}.
+ */
+Data.Long.prototype.getLowBits = function() {
+    return this.low;
+};
+
+/**
+ * @method getLowBitsUnsigned
+ * @memberof! proton.Data.Long#
+ * @returns {number} the least significant word of a {@link proton.Data.Long}
+ *          as an unsigned value.
+ */
+Data.Long.prototype.getLowBitsUnsigned = function() {
+    return (this.low >= 0) ? this.low : Data.Long.TWO_PWR_32_DBL_ + this.low;
+};
+
+/**
+ * @method toNumber
+ * @memberof! proton.Data.Long#
+ * @returns {number} a native JavaScript number (with possible loss of precision).
+ */
+Data.Long.prototype.toNumber = function() {
+    return (this.high * Data.Long.TWO_PWR_32_DBL_) + this.getLowBitsUnsigned();
+};
+
+/**
+ * @method toString
+ * @memberof! proton.Data.Long#
+ * @returns {string} the String form of a {@link proton.Data.Long}.
+ */
+Data.Long.prototype.toString = function() {
+    return this.high + ':' + this.getLowBitsUnsigned();
+};
+
diff --git a/proton-c/bindings/javascript/data-symbol.js b/proton-c/bindings/javascript/data-symbol.js
new file mode 100644
index 0000000..c742acb
--- /dev/null
+++ b/proton-c/bindings/javascript/data-symbol.js
@@ -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.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                             proton.Data.Symbol                            */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Create a proton.Data.Symbol.
+ * @classdesc
+ * This class represents an AMQP Symbol. This class is necessary primarily as a
+ * way to enable us to distinguish between a native String and a Symbol in the
+ * JavaScript type system.
+ * @constructor proton.Data.Symbol
+ * @param {string} s a symbol.
+ */
+Data['Symbol'] = function(s) { // Data.Symbol Constructor.
+    this.value = s;
+};
+
+/**
+ * @method toString
+ * @memberof! proton.Data.Symbol#
+ * @returns {string} the String form of a {@link proton.Data.Symbol}.
+ */
+Data['Symbol'].prototype.toString = Data['Symbol'].prototype.valueOf = function() {
+    return this.value;
+};
+
+/**
+ * Compare two instances of proton.Data.Symbol for equality.
+ * @method equals
+ * @memberof! proton.Data.Symbol#
+ * @param {proton.Data.Symbol} rhs the instance we wish to compare this instance with.
+ * @returns {boolean} true iff the two compared instances are equal.
+ */
+Data['Symbol'].prototype['equals'] = function(rhs) {
+    return this.toString() === rhs.toString();
+};
+
diff --git a/proton-c/bindings/javascript/data-typed-number.js b/proton-c/bindings/javascript/data-typed-number.js
new file mode 100644
index 0000000..034d4ec
--- /dev/null
+++ b/proton-c/bindings/javascript/data-typed-number.js
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                             proton.Data.TypedNumber                       */
+/*                                                                           */
+/*****************************************************************************/
+
+// ---------------------- JavaScript Number Extensions ------------------------ 
+
+Number.prototype['ubyte'] = function() {
+    return new Data.TypedNumber('UBYTE', this);
+};
+
+Number.prototype['byte'] = function() {
+    return new Data.TypedNumber('BYTE', this);
+};
+
+Number.prototype['ushort'] = function() {
+    return new Data.TypedNumber('USHORT', this);
+};
+
+Number.prototype['short'] = function() {
+    return new Data.TypedNumber('SHORT', this);
+};
+
+Number.prototype['uint'] = function() {
+    return new Data.TypedNumber('UINT', this);
+};
+
+Number.prototype['int'] = function() {
+    return new Data.TypedNumber('INT', this);
+};
+
+Number.prototype['ulong'] = function() {
+    return new Data.TypedNumber('ULONG', this);
+};
+
+Number.prototype['long'] = function() {
+    return new Data.TypedNumber('LONG', this);
+};
+
+Number.prototype['float'] = function() {
+    return new Data.TypedNumber('FLOAT', this);
+};
+
+Number.prototype['double'] = function() {
+    return new Data.TypedNumber('DOUBLE', this);
+};
+
+Number.prototype['char'] = function() {
+    return new Data.TypedNumber('CHAR', this);
+};
+
+String.prototype['char'] = function() {
+    return new Data.TypedNumber('CHAR', this.charCodeAt(0));
+};
+
+// ------------------------- proton.Data.TypedNumber -------------------------- 
+/**
+ * Create a proton.Data.TypedNumber.
+ * @classdesc
+ * This class is a simple wrapper class that allows a "type" to be recorded for
+ * a number. The idea is that the JavaScript Number class is extended with extra
+ * methods to allow numbers to be "modified" to TypedNumbers, so for example
+ * 1.0.float() would modify 1.0 by returning a TypedNumber with type = FLOAT
+ * and value = 1. The strings used for type correspond to the names of the Data
+ * put* methods e.g. UBYTE, BYTE, USHORT, SHORT, UINT, INT, ULONG, LONG, FLOAT,
+ * DOUBLE, CHAR so that the correct method to call can be derived from the type.
+ * @constructor proton.Data.TypedNumber
+ * @param {(string|number)} type the type of the Number either as a string or number.
+ *        Stored internally as a string corresponding to one of the TypeNames.
+ * @param {number} value the value of the Number.
+ */
+// Use dot notation as it is a "protected" inner class not exported from the closure.
+Data.TypedNumber = function(type, value) { // Data.TypedNumber Constructor.
+    this.type  = (typeof type === 'number') ? Data['TypeNames'][type] : type;
+    this.value = value;
+};
+
+/**
+ * @method toString
+ * @memberof! proton.Data.TypedNumber#
+ * @returns {string} the String form of a {@link proton.Data.TypedNumber}.
+ */
+Data.TypedNumber.prototype.toString = Data.TypedNumber.prototype.valueOf = function() {
+    return +this.value;
+};
+
+
diff --git a/proton-c/bindings/javascript/data-uuid.js b/proton-c/bindings/javascript/data-uuid.js
new file mode 100644
index 0000000..4fee84a
--- /dev/null
+++ b/proton-c/bindings/javascript/data-uuid.js
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                             proton.Data.Uuid                              */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Create a proton.Data.Uuid which is a type 4 UUID.
+ * @classdesc
+ * This class represents a type 4 UUID, wich may use crypto libraries to generate
+ * the UUID if supported by the platform (e.g. node.js or a modern browser)
+ * @constructor proton.Data.Uuid
+ * @param {number|Array|string} u a UUID. If null a type 4 UUID is generated wich may use crypto if
+ *        supported by the platform. If u is an emscripten "pointer" we copy the
+ *        data from that. If u is a JavaScript Array we use it as-is. If u is a
+ *        String then we try to parse that as a UUID.
+ * @property {Array} uuid is the compact array form of the UUID.
+ */
+Data['Uuid'] = function(u) { // Data.Uuid Constructor.
+    // Helper to copy from emscriptem allocated storage into JavaScript Array.
+    function _p2a(p) {
+        var uuid = new Array(16);
+        for (var i = 0; i < 16; i++) {
+            uuid[i] = getValue(p + i, 'i8') & 0xFF; // & 0xFF converts to unsigned.
+        }
+        return uuid;
+    };
+
+    if (!u) { // Generate UUID using emscriptem's uuid_generate implementation.
+        var sp = Runtime.stackSave();
+        var p = allocate(16, 'i8', ALLOC_STACK); // Create temporary pointer storage.
+        _uuid_generate(p);      // Generate UUID into allocated pointer.
+        this['uuid'] = _p2a(p); // Copy from allocated storage into JavaScript Array.
+        Runtime.stackRestore(sp);
+    } else if (Data.isNumber(u)) { // Use pointer that has been passed in.
+        this['uuid'] = _p2a(u);    // Copy from allocated storage into JavaScript Array.
+    } else if (Data.isArray(u)) { // Use array that has been passed in.
+        this['uuid'] = u; // Just use the JavaScript Array.
+    } else if (Data.isString(u)) { // Parse String form UUID.
+        if (u.length === 36) {
+            var i = 0;
+            var uuid = new Array(16);
+            u.toLowerCase().replace(/[0-9a-f]{2}/g, function(byte) {
+                if (i < 16) {
+                    uuid[i++] = parseInt(byte, 16);
+                }
+            });
+            this['uuid'] = uuid;
+        }
+    }
+    this.string = null;
+};
+
+/**
+ * Returns the string representation of the proton.Data.Uuid.
+ * @method toString
+ * @memberof! proton.Data.Uuid#
+ * @returns {string} the String
+ *          /[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}/
+ *          form of a {@link proton.Data.Uuid}.
+ */
+Data['Uuid'].prototype.toString = Data['Uuid'].prototype.valueOf = function() {
+    if (!this.string) { // Check if we've cached the string version.
+        var i = 0;
+        var uu = this['uuid'];
+        var uuid = 'xxxx-xx-xx-xx-xxxxxx'.replace(/[x]/g, function(c) {
+            var r = uu[i].toString(16);
+            r = (r.length === 1) ? '0' + r : r; // Zero pad single digit hex values
+            i++;
+            return r;
+        });
+        this.string = uuid;
+    }
+    return this.string;
+};
+
+/**
+ * Compare two instances of proton.Data.Uuid for equality.
+ * @method equals
+ * @memberof! proton.Data.Uuid#
+ * @param {proton.Data.Uuid} rhs the instance we wish to compare this instance with.
+ * @returns {boolean} true iff the two compared instances are equal.
+ */
+Data['Uuid'].prototype['equals'] = function(rhs) {
+    return this.toString() === rhs.toString();
+};
+
diff --git a/proton-c/bindings/javascript/data.js b/proton-c/bindings/javascript/data.js
new file mode 100644
index 0000000..018c5fb
--- /dev/null
+++ b/proton-c/bindings/javascript/data.js
@@ -0,0 +1,1577 @@
+/*
+ * 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.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                                    Data                                   */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Constructs a proton.Data instance.
+ * @classdesc
+ * The Data class provides an interface for decoding, extracting, creating, and
+ * encoding arbitrary AMQP data. A Data object contains a tree of AMQP values.
+ * Leaf nodes in this tree correspond to scalars in the AMQP type system such as
+ * ints<INT> or strings<STRING>. Non-leaf nodes in this tree correspond to compound
+ * values in the AMQP type system such as lists<LIST>, maps<MAP>, arrays<ARRAY>,
+ * or described values<DESCRIBED>. The root node of the tree is the Data object
+ * itself and can have an arbitrary number of children.
+ * <p>
+ * A Data object maintains the notion of the current sibling node and a current
+ * parent node. Siblings are ordered within their parent. Values are accessed
+ * and/or added by using the next, prev, enter, and exit methods to navigate to
+ * the desired location in the tree and using the supplied variety of put* and
+ * get* methods to access or add a value of the desired type.
+ * <p>
+ * The put* methods will always add a value after the current node in the tree.
+ * If the current node has a next sibling the put* method will overwrite the value
+ * on this node. If there is no current node or the current node has no next
+ * sibling then one will be added. The put* methods always set the added/modified
+ * node to the current node. The get* methods read the value of the current node
+ * and do not change which node is current.
+ * @constructor proton.Data
+ * @param {number} data an optional pointer to a pn_data_t instance. If supplied
+ *        the underlying data is "owned" by another object (for example a Message)
+ *        and that object is assumed to be responsible for freeing the data if
+ *        necessary. If no data is supplied then the Data is stand-alone and the
+ *        client application is responsible for freeing the underlying data via
+ *        a call to free().
+ * @param {boolean} decodeBinaryAsString if set decode any AMQP Binary payload
+ *        objects as strings. This can be useful as the data in Binary objects
+ *        will be overwritten with subsequent calls to get, so they must be
+ *        explicitly copied. Needless to say it is only safe to set this flag if
+ *        you know that the data you are dealing with is actually a string, for
+ *        example C/C++ applications often seem to encode strings as AMQP binary,
+ *        a common cause of interoperability problems.
+ */
+Module['Data'] = function(data, decodeBinaryAsString) { // Data Constructor.
+    if (!data) {
+        this._data = _pn_data(16); // Default capacity is 16
+        this['free'] = function() {
+            _pn_data_free(this._data);
+            // Set free to a null function to prevent possibility of a "double free".
+            this['free'] = function() {};
+        };
+    } else {
+        this._data = data;
+        this['free'] = function() {};
+    }
+    this._decodeBinaryAsString = decodeBinaryAsString;
+};
+
+// Expose constructor as package scope variable to make internal calls less verbose.
+var Data = Module['Data'];
+
+// Expose prototype as a variable to make method declarations less verbose.
+var _Data_ = Data.prototype;
+
+// ************************** Class properties ********************************
+
+Data['NULL']       = 1;
+Data['BOOL']       = 2;
+Data['UBYTE']      = 3;
+Data['BYTE']       = 4;
+Data['USHORT']     = 5;
+Data['SHORT']      = 6;
+Data['UINT']       = 7;
+Data['INT']        = 8;
+Data['CHAR']       = 9;
+Data['ULONG']      = 10;
+Data['LONG']       = 11;
+Data['TIMESTAMP']  = 12;
+Data['FLOAT']      = 13;
+Data['DOUBLE']     = 14;
+Data['DECIMAL32']  = 15;
+Data['DECIMAL64']  = 16;
+Data['DECIMAL128'] = 17;
+Data['UUID']       = 18;
+Data['BINARY']     = 19;
+Data['STRING']     = 20;
+Data['SYMBOL']     = 21;
+Data['DESCRIBED']  = 22;
+Data['ARRAY']      = 23;
+Data['LIST']       = 24;
+Data['MAP']        = 25;
+
+/**
+ * Look-up table mapping proton-c types to the accessor method used to
+ * deserialise the type. N.B. this is a simple Array and not a map because the
+ * types that we get back from pn_data_type are integers from the pn_type_t enum.
+ * @property {Array<String>} TypeNames ['NULL', 'NULL', 'BOOL', 'UBYTE', 'BYTE',
+ * 'USHORT', 'SHORT', 'UINT', 'INT', 'CHAR', 'ULONG', 'LONG', 'TIMESTAMP',
+ * 'FLOAT', 'DOUBLE', 'DECIMAL32', 'DECIMAL64', 'DECIMAL128', 'UUID',
+ * 'BINARY', 'STRING', 'SYMBOL', 'DESCRIBED', 'ARRAY', 'LIST', 'MAP']
+ * @memberof! proton.Data
+ */
+Data['TypeNames'] = [
+    'NULL',       // 0
+    'NULL',       // PN_NULL       = 1
+    'BOOL',       // PN_BOOL       = 2
+    'UBYTE',      // PN_UBYTE      = 3
+    'BYTE',       // PN_BYTE       = 4
+    'USHORT',     // PN_USHORT     = 5
+    'SHORT',      // PN_SHORT      = 6
+    'UINT',       // PN_UINT       = 7
+    'INT',        // PN_INT        = 8
+    'CHAR',       // PN_CHAR       = 9
+    'ULONG',      // PN_ULONG      = 10
+    'LONG',       // PN_LONG       = 11
+    'TIMESTAMP',  // PN_TIMESTAMP  = 12
+    'FLOAT',      // PN_FLOAT      = 13
+    'DOUBLE',     // PN_DOUBLE     = 14
+    'DECIMAL32',  // PN_DECIMAL32  = 15
+    'DECIMAL64',  // PN_DECIMAL64  = 16
+    'DECIMAL128', // PN_DECIMAL128 = 17
+    'UUID',       // PN_UUID       = 18
+    'BINARY',     // PN_BINARY     = 19
+    'STRING',     // PN_STRING     = 20
+    'SYMBOL',     // PN_SYMBOL     = 21
+    'DESCRIBED',  // PN_DESCRIBED  = 22
+    'ARRAY',      // PN_ARRAY      = 23
+    'LIST',       // PN_LIST       = 24
+    'MAP'         // PN_MAP        = 25
+];
+
+// *************************** Class methods **********************************
+
+/**
+ * Test if a given Object is a JavaScript Array.
+ * @method isArray
+ * @memberof! proton.Data
+ * @param {object} o the Object that we wish to test.
+ * @returns {boolean} true iff the Object is a JavaScript Array.
+ */
+Data.isArray = Array.isArray || function(o) {
+    return Object.prototype.toString.call(o) === '[object Array]';
+};
+
+/**
+ * Test if a given Object is a JavaScript Number.
+ * @method isNumber
+ * @memberof! proton.Data
+ * @param {object} o the Object that we wish to test.
+ * @returns {boolean} true iff the Object is a JavaScript Number.
+ */
+Data.isNumber = function(o) {
+    return typeof o === 'number' || 
+          (typeof o === 'object' && Object.prototype.toString.call(o) === '[object Number]');
+};
+
+/**
+ * Test if a given Object is a JavaScript String.
+ * @method isString
+ * @memberof! proton.Data
+ * @param {object} o the Object that we wish to test.
+ * @returns {boolean} true iff the Object is a JavaScript String.
+ */
+Data.isString = function(o) {
+    return typeof o === 'string' ||
+          (typeof o === 'object' && Object.prototype.toString.call(o) === '[object String]');
+};
+
+/**
+ * Test if a given Object is a JavaScript Boolean.
+ * @method isBoolean
+ * @memberof! proton.Data
+ * @param {object} o the Object that we wish to test.
+ * @returns {boolean} true iff the Object is a JavaScript Boolean.
+ */
+Data.isBoolean = function(o) {
+    return typeof o === 'boolean' ||
+          (typeof o === 'object' && Object.prototype.toString.call(o) === '[object Boolean]');
+};
+
+
+// ************************* Protected methods ********************************
+
+// We use the dot notation rather than associative array form for protected
+// methods so they are visible to this "package", but the Closure compiler will
+// minify and obfuscate names, effectively making a defacto "protected" method.
+
+/**
+ * This helper method checks the supplied error code, converts it into an
+ * exception and throws the exception. This method will try to use the message
+ * populated in pn_data_error(), if present, but if not it will fall
+ * back to using the basic error code rendering from pn_code().
+ * @param code the error code to check.
+ */
+_Data_._check = function(code) {
+    if (code < 0) {
+        var errno = this['getErrno']();
+        var message = errno ? this['getError']() : Pointer_stringify(_pn_code(code));
+
+        throw new Module['DataError'](message);
+    } else {
+        return code;
+    }
+};
+
+
+// *************************** Public methods *********************************
+
+/**
+ * @method getErrno
+ * @memberof! proton.Data#
+ * @returns {number} the most recent error message code.
+ */
+_Data_['getErrno'] = function() {
+    return _pn_data_errno(this._data);
+};
+
+/**
+ * @method getError
+ * @memberof! proton.Data#
+ * @returns {string} the most recent error message as a String.
+ */
+_Data_['getError'] = function() {
+    return Pointer_stringify(_pn_error_text(_pn_data_error(this._data)));
+};
+
+/**
+ * Clears the data object.
+ * @method clear
+ * @memberof! proton.Data#
+ */
+_Data_['clear'] = function() {
+    _pn_data_clear(this._data);
+};
+
+/**
+ * Clears current node and sets the parent to the root node.  Clearing the current
+ * node sets it _before_ the first node, calling next() will advance to the first node.
+ * @method rewind
+ * @memberof! proton.Data#
+ */
+_Data_['rewind'] = function() {
+    _pn_data_rewind(this._data);
+};
+
+/**
+ * Advances the current node to its next sibling and returns its type. If there
+ * is no next sibling the current node remains unchanged and null is returned.
+ * @method next
+ * @memberof! proton.Data#
+ * @returns {number} the type of the next sibling or null.
+ */
+_Data_['next'] = function() {
+    var found = _pn_data_next(this._data);
+    if (found) {
+        return this.type();
+    } else {
+        return null;
+    }
+};
+
+/**
+ * Advances the current node to its previous sibling and returns its type. If there
+ * is no previous sibling the current node remains unchanged and null is returned.
+ * @method prev
+ * @memberof! proton.Data#
+ * @returns {number} the type of the previous sibling or null.
+ */
+_Data_['prev'] = function() {
+    var found = _pn_data_prev(this._data);
+    if (found) {
+        return this.type();
+    } else {
+        return null;  
+    }
+};
+
+/**
+ * Sets the parent node to the current node and clears the current node. Clearing
+ * the current node sets it _before_ the first child, next() advances to the first child.
+ * @method enter
+ * @memberof! proton.Data#
+ */
+_Data_['enter'] = function() {
+    return (_pn_data_enter(this._data) > 0);
+};
+
+/**
+ * Sets the current node to the parent node and the parent node to its own parent.
+ * @method exit
+ * @memberof! proton.Data#
+ */
+_Data_['exit'] = function() {
+    return (_pn_data_exit(this._data) > 0);
+};
+
+/**
+ * Look up a value by name. N.B. Need to use getObject() to retrieve the actual
+ * value after lookup suceeds.
+ * @method lookup
+ * @memberof! proton.Data#
+ * @param {string} name the name of the property to look up.
+ * @returns {boolean} true iff the lookup succeeded.
+ */
+_Data_['lookup'] = function(name) {
+    var sp = Runtime.stackSave();
+    var lookup = _pn_data_lookup(this._data, allocate(intArrayFromString(name), 'i8', ALLOC_STACK));
+    Runtime.stackRestore(sp);
+    return (lookup > 0);
+};
+
+// TODO document - not quite sure what these are for?
+_Data_['narrow'] = function() {
+    _pn_data_narrow(this._data);
+};
+
+_Data_['widen'] = function() {
+    _pn_data_widen(this._data);
+};
+
+/**
+ * @method type
+ * @memberof! proton.Data#
+ * @returns {number} the type of the current node or null if the type is unknown.
+ */
+_Data_['type'] = function() {
+    var dtype = _pn_data_type(this._data);
+    if (dtype === -1) {
+        return null;
+    } else {
+        return dtype;
+    }
+};
+
+/**
+ * Return a Binary representation of the data encoded in AMQP format. N.B. the
+ * returned {@link proton.Data.Binary} "owns" the underlying raw data and is thus
+ * responsible for freeing it or passing it to a method that consumes a Binary
+ * such as {@link proton.Data.decode} or {@link proton.Data.putBINARY}.
+ * @method encode
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Binary} a representation of the data encoded in AMQP format.
+ */
+_Data_['encode'] = function() {
+    var size = 1024;
+    while (true) {
+        var bytes = _malloc(size); // Allocate storage from emscripten heap.
+        var cd = _pn_data_encode(this._data, bytes, size);
+
+        if (cd === Module['Error']['OVERFLOW']) {
+            _free(bytes);
+            size *= 2;
+        } else if (cd >= 0) {
+            return new Data['Binary'](cd, bytes);
+        } else {
+            _free(bytes);
+            this._check(cd);
+            return;
+        }
+    }
+};
+
+/**
+ * Decodes the first value from supplied Binary AMQP data and returns a new
+ * {@link proton.Data.Binary} containing the remainder of the data or null if
+ * all the supplied data has been consumed. N.B. this method "consumes" data
+ * from a {@link proton.Data.Binary} in other words it takes responsibility for
+ * the underlying data and frees the raw data from the Binary.
+ * @method decode
+ * @memberof! proton.Data#
+ * @param {proton.Data.Binary} encoded the AMQP encoded binary data.
+ * @returns {proton.Data.Binary} a Binary containing the remaining bytes or null
+ *          if all the data has been consumed.
+ */
+_Data_['decode'] = function(encoded) {
+    var start = encoded.start;
+    var size = encoded.size;
+    var consumed = this._check(_pn_data_decode(this._data, start, size));
+
+    size = size - consumed;
+    start = _malloc(size); // Allocate storage from emscripten heap.
+    _memcpy(start, encoded.start + consumed, size);
+
+    encoded['free'](); // Free the original Binary.
+    return size > 0 ? new Data['Binary'](size, start) : null;
+};
+
+/**
+ * Puts a list node. Elements may be filled by entering the list
+ * node and putting element values.
+ * <pre>
+ *  var data = new proton.Data();
+ *  data.putLISTNODE();
+ *  data.enter();
+ *  data.putINT(1);
+ *  data.putINT(2);
+ *  data.putINT(3);
+ *  data.exit();
+ * </pre>
+ * @method putLISTNODE
+ * @memberof! proton.Data#
+ */
+_Data_['putLISTNODE'] = function() {
+    this._check(_pn_data_put_list(this._data));
+};
+
+/**
+ * Puts a map node. Elements may be filled by entering the map node
+ * and putting alternating key value pairs.
+ * <pre>
+ *  var data = new proton.Data();
+ *  data.putMAPNODE();
+ *  data.enter();
+ *  data.putSTRING('key');
+ *  data.putSTRING('value');
+ *  data.exit();
+ * </pre>
+ * @method putMAPNODE
+ * @memberof! proton.Data#
+ */
+_Data_['putMAPNODE'] = function() {
+    this._check(_pn_data_put_map(this._data));
+};
+
+/**
+ * Puts an array node. Elements may be filled by entering the array node and
+ * putting the element values. The values must all be of the specified array
+ * element type. If an array is described then the first child value of the array
+ * is the descriptor and may be of any type.
+ * <pre>
+ *  var data = new proton.Data();
+ *  data.putARRAYNODE(false, proton.Data.INT);
+ *  data.enter();
+ *  data.putINT(1);
+ *  data.putINT(2);
+ *  data.putINT(3);
+ *  data.exit();
+ *
+ *  data.putARRAYNODE(true, proton.Data.DOUBLE);
+ *  data.enter();
+ *  data.putSYMBOL('array-descriptor');
+ *  data.putDOUBLE(1.1);
+ *  data.putDOUBLE(1.2);
+ *  data.putDOUBLE(1.3);
+ *  data.exit();
+ * </pre>
+ * @method putARRAYNODE
+ * @param {boolean} described specifies whether the array is described.
+ * @param {number} type the type of the array elements.
+ * @memberof! proton.Data#
+ */
+_Data_['putARRAYNODE'] = function(described, type) {
+    this._check(_pn_data_put_array(this._data, described, type));
+};
+
+/**
+ * Puts a described node. A described node has two children, the descriptor and
+ * value. These are specified by entering the node and putting the desired values.
+ * <pre>
+ *  var data = new proton.Data();
+ *  data.putDESCRIBEDNODE();
+ *  data.enter();
+ *  data.putSYMBOL('value-descriptor');
+ *  data.putSTRING('the value');
+ *  data.exit();
+ * </pre>
+ * @method putDESCRIBEDNODE
+ * @memberof! proton.Data#
+ */
+_Data_['putDESCRIBEDNODE'] = function() {
+    this._check(_pn_data_put_described(this._data));
+};
+
+/**
+ * Puts a null value.
+ * @method putNULL
+ * @memberof! proton.Data#
+ */
+_Data_['putNULL'] = function() {
+    this._check(_pn_data_put_null(this._data));
+};
+
+/**
+ * Puts a boolean value.
+ * @method putBOOL
+ * @memberof! proton.Data#
+ * @param {boolean} b a boolean value.
+ */
+_Data_['putBOOL'] = function(b) {
+    this._check(_pn_data_put_bool(this._data, b));
+};
+
+/**
+ * Puts a unsigned byte value.
+ * @method putUBYTE
+ * @memberof! proton.Data#
+ * @param {number} ub an integral value.
+ */
+_Data_['putUBYTE'] = function(ub) {
+    this._check(_pn_data_put_ubyte(this._data, ub));
+};
+
+/**
+ * Puts a signed byte value.
+ * @method putBYTE
+ * @memberof! proton.Data#
+ * @param {number} b an integral value.
+ */
+_Data_['putBYTE'] = function(b) {
+    this._check(_pn_data_put_byte(this._data, b));
+};
+
+/**
+ * Puts a unsigned short value.
+ * @method putUSHORT
+ * @memberof! proton.Data#
+ * @param {number} us an integral value.
+ */
+_Data_['putUSHORT'] = function(us) {
+    this._check(_pn_data_put_ushort(this._data, us));
+};
+
+/**
+ * Puts a signed short value.
+ * @method putSHORT
+ * @memberof! proton.Data#
+ * @param {number} s an integral value.
+ */
+_Data_['putSHORT'] = function(s) {
+    this._check(_pn_data_put_short(this._data, s));
+};
+
+/**
+ * Puts a unsigned integer value.
+ * @method putUINT
+ * @memberof! proton.Data#
+ * @param {number} ui an integral value.
+ */
+_Data_['putUINT'] = function(ui) {
+    this._check(_pn_data_put_uint(this._data, ui));
+};
+
+/**
+ * Puts a signed integer value.
+ * @method putINT
+ * @memberof! proton.Data#
+ * @param {number} i an integral value.
+ */
+_Data_['putINT'] = function(i) {
+    this._check(_pn_data_put_int(this._data, i));
+};
+
+/**
+ * Puts a signed char value.
+ * @method putCHAR
+ * @memberof! proton.Data#
+ * @param {(string|number)} c a single character expressed either as a string or a number.
+ */
+_Data_['putCHAR'] = function(c) {
+    c = Data.isString(c) ? c.charCodeAt(0) : c;
+    this._check(_pn_data_put_char(this._data, c));
+};
+
+/**
+ * Puts a unsigned long value. N.B. large values can suffer from a loss of
+ * precision as JavaScript numbers are restricted to 64 bit double values.
+ * @method putULONG
+ * @memberof! proton.Data#
+ * @param {number} ul an integral value.
+ */
+_Data_['putULONG'] = function(ul) {
+    // If the supplied number exceeds the range of Data.Long invert it before
+    // constructing the Data.Long.
+    ul = (ul >= Data.Long.TWO_PWR_63_DBL_) ? (ul = -(Data.Long.TWO_PWR_64_DBL_ - ul)) : ul;
+    var long = Data.Long.fromNumber(ul);
+    this._check(_pn_data_put_ulong(this._data, long.getLowBitsUnsigned(), long.getHighBits()));
+};
+
+/**
+ * Puts a signed long value. N.B. large values can suffer from a loss of
+ * precision as JavaScript numbers are restricted to 64 bit double values.
+ * @method putLONG
+ * @memberof! proton.Data#
+ * @param {number} i an integral value.
+ */
+_Data_['putLONG'] = function(l) {
+    var long = Data.Long.fromNumber(l);
+    this._check(_pn_data_put_long(this._data, long.getLowBitsUnsigned(), long.getHighBits()));
+};
+
+/**
+ * Puts a timestamp.
+ * @method putTIMESTAMP
+ * @memberof! proton.Data#
+ * @param {(number|Date)} d a Date value.
+ */
+_Data_['putTIMESTAMP'] = function(d) {
+    // Note that a timestamp is a 64 bit number so we have to use a proton.Data.Long.
+    var timestamp = Data.Long.fromNumber(d.valueOf());
+    this._check(_pn_data_put_timestamp(this._data, timestamp.getLowBitsUnsigned(), timestamp.getHighBits()));
+};
+
+/**
+ * Puts a float value. N.B. converting between floats and doubles is imprecise
+ * so the resulting value might not quite be what you expect.
+ * @method putFLOAT
+ * @memberof! proton.Data#
+ * @param {number} f a floating point value.
+ */
+_Data_['putFLOAT'] = function(f) {
+    this._check(_pn_data_put_float(this._data, f));
+};
+
+/**
+ * Puts a double value.
+ * @method putDOUBLE
+ * @memberof! proton.Data#
+ * @param {number} d a floating point value.
+ */
+_Data_['putDOUBLE'] = function(d) {
+    this._check(_pn_data_put_double(this._data, d));
+};
+
+/**
+ * Puts a decimal32 value.
+ * @method putDECIMAL32
+ * @memberof! proton.Data#
+ * @param {number} d a decimal32 value.
+ */
+_Data_['putDECIMAL32'] = function(d) {
+    this._check(_pn_data_put_decimal32(this._data, d));
+};
+
+/**
+ * Puts a decimal64 value.
+ * @method putDECIMAL64
+ * @memberof! proton.Data#
+ * @param {number} d a decimal64 value.
+ */
+_Data_['putDECIMAL64'] = function(d) {
+    this._check(_pn_data_put_decimal64(this._data, d));
+};
+
+/**
+ * Puts a decimal128 value.
+ * @method putDECIMAL128
+ * @memberof! proton.Data#
+ * @param {number} d a decimal128 value.
+ */
+_Data_['putDECIMAL128'] = function(d) {
+    this._check(_pn_data_put_decimal128(this._data, d));
+};
+
+/**
+ * Puts a UUID value.
+ * @method putUUID
+ * @memberof! proton.Data#
+ * @param {proton.Data.Uuid} u a uuid value
+ */
+_Data_['putUUID'] = function(u) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_data_put_uuid(this._data, allocate(u['uuid'], 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Puts a binary value consuming the underlying raw data in the process.
+ * @method putBINARY
+ * @memberof! proton.Data#
+ * @param {proton.Data.Binary} b a binary value.
+ */
+_Data_['putBINARY'] = function(b) {
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_data_put_binary(data, pn_bytes(b.size, b.start));
+
+    // Here's the quirky bit, pn_bytes actually returns pn_bytes_t *by value* but
+    // the low-level code handles this *by pointer* so we first need to allocate
+    // 8 bytes storage for {size, start} on the emscripten stack and then we
+    // pass the pointer to that storage as the first parameter to the pn_bytes.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_bytes(bytes, b.size, b.start);
+
+    // The compiled pn_data_put_binary takes the pn_bytes_t by reference not value.
+    this._check(_pn_data_put_binary(this._data, bytes));
+
+    // After calling _pn_data_put_binary the underlying Data object "owns" the
+    // binary data, so we can call free on the proton.Data.Binary instance to
+    // release any storage it has acquired back to the emscripten heap.
+    b['free']();
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Puts a unicode string value.
+ * @method putSTRING
+ * @memberof! proton.Data#
+ * @param {string} s a unicode string value.
+ */
+_Data_['putSTRING'] = function(s) {
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_data_put_string(data, pn_bytes(strlen(text), text));
+
+    // First create an array from the JavaScript String using the intArrayFromString
+    // helper function (from emscripten/src/preamble.js). We use this idiom in a
+    // few places but here we create array as a separate var as we need its length.
+    var array = intArrayFromString(s, true); // The true means don't add NULL.
+    // Allocate temporary storage for the array on the emscripten stack.
+    var str = allocate(array, 'i8', ALLOC_STACK);
+
+    // Here's the quirky bit, pn_bytes actually returns pn_bytes_t *by value* but
+    // the low-level code handles this *by pointer* so we first need to allocate
+    // 8 bytes storage for {size, start} on the emscripten stack and then we
+    // pass the pointer to that storage as the first parameter to the pn_bytes.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_bytes(bytes, array.length, str);
+
+    // The compiled pn_data_put_string takes the pn_bytes_t by reference not value.
+    this._check(_pn_data_put_string(this._data, bytes));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Puts a symbolic value. According to the AMQP 1.0 Specification Symbols are
+ * values from a constrained domain. Although the set of possible domains is
+ * open-ended, typically the both number and size of symbols in use for any
+ * given application will be small, e.g. small enough that it is reasonable to
+ * cache all the distinct values. Symbols are encoded as ASCII characters.
+ * @method putSYMBOL
+ * @memberof! proton.Data#
+ * @param {proton.Data.Symbol|string} s the symbol name.
+ */
+_Data_['putSYMBOL'] = function(s) {
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_data_put_symbol(data, pn_bytes(strlen(text), text));
+
+    // First create an array from the JavaScript String using the intArrayFromString
+    // helper function (from emscripten/src/preamble.js). We use this idiom in a
+    // few places but here we create array as a separate var as we need its length.
+    var array = intArrayFromString(s, true); // The true means don't add NULL.
+    // Allocate temporary storage for the array on the emscripten stack.
+    var str = allocate(array, 'i8', ALLOC_STACK);
+
+    // Here's the quirky bit, pn_bytes actually returns pn_bytes_t *by value* but
+    // the low-level code handles this *by pointer* so we first need to allocate
+    // 8 bytes storage for {size, start} on the emscripten stack and then we
+    // pass the pointer to that storage as the first parameter to the pn_bytes.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_bytes(bytes, array.length, str);
+
+    // The compiled pn_data_put_symbol takes the pn_bytes_t by reference not value.
+    this._check(_pn_data_put_symbol(this._data, bytes));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * If the current node is a list node, return the number of elements,
+ * otherwise return zero. List elements can be accessed by entering
+ * the list.
+ * <pre>
+ *  var count = data.getLISTNODE();
+ *  data.enter();
+ *  for (var i = 0; i < count; i++) {
+ *      var type = data.next();
+ *      if (type === proton.Data.STRING) {
+ *          console.log(data.getSTRING());
+ *      }
+ *  }
+ *  data.exit();
+ * </pre>
+ * @method getLISTNODE
+ * @memberof! proton.Data#
+ * @returns {number} the number of elements if the current node is a list,
+ *          zero otherwise.
+ */
+_Data_['getLISTNODE'] = function() {
+    return _pn_data_get_list(this._data);
+};
+
+/**
+ * If the current node is a map, return the number of child elements,
+ * otherwise return zero. Key value pairs can be accessed by entering
+ * the map.
+ * <pre>
+ *  var count = data.getMAPNODE();
+ *  data.enter();
+ *  for (var i = 0; i < count/2; i++) {
+ *      var type = data.next();
+ *      if (type === proton.Data.STRING) {
+ *          console.log(data.getSTRING());
+ *      }
+ *  }
+ *  data.exit();
+ * </pre>
+ * @method getMAPNODE
+ * @memberof! proton.Data#
+ * @returns {number} the number of elements if the current node is a list,
+ *          zero otherwise.
+ */
+_Data_['getMAPNODE'] = function() {
+    return _pn_data_get_map(this._data);
+};
+
+/**
+ * If the current node is an array, return an object containing the tuple of the
+ * element count, a boolean indicating whether the array is described, and the
+ * type of each element, otherwise return {count: 0, described: false, type: null).
+ * Array data can be accessed by entering the array.
+ * <pre>
+ *  // Read an array of strings with a symbolic descriptor
+ *  var metadata = data.getARRAYNODE();
+ *  var count = metadata.count;
+ *  data.enter();
+ *  data.next();
+ *  console.log("Descriptor:" + data.getSYMBOL());
+ *  for (var i = 0; i < count; i++) {
+ *      var type = data.next();
+ *      console.log("Element:" + data.getSTRING());
+ *  }
+ *  data.exit();
+ * </pre>
+ * @method getARRAYNODE
+ * @memberof! proton.Data#
+ * @returns {object} the tuple of the element count, a boolean indicating whether
+ *          the array is described, and the type of each element.
+ */
+_Data_['getARRAYNODE'] = function() {
+    var count = _pn_data_get_array(this._data);
+    var described = (_pn_data_is_array_described(this._data) > 0);
+    var type = _pn_data_get_array_type(this._data);
+    type = (type == -1) ? null : type;
+    return {'count': count, 'described': described, 'type': type};
+};
+
+/**
+ * Checks if the current node is a described node. The descriptor and value may
+ * be accessed by entering the described node.
+ * <pre>
+ *  // read a symbolically described string
+ *  assert(data.isDESCRIBEDNODE()); // will error if the current node is not described
+ *  data.enter();
+ *  console.log(data.getSYMBOL());
+ *  console.log(data.getSTRING());
+ *  data.exit();
+ * </pre>
+ * @method isDESCRIBEDNODE
+ * @memberof! proton.Data#
+ * @returns {boolean} true iff the current node is a described, false otherwise.
+ */
+_Data_['isDESCRIBEDNODE'] = function() {
+    return _pn_data_is_described(this._data);
+};
+
+/**
+ * @method getNULL
+ * @memberof! proton.Data#
+ * @returns a null value.
+ */
+_Data_['getNULL'] = function() {
+    return null;
+};
+
+/**
+ * Checks if the current node is a null.
+ * @method isNULL
+ * @memberof! proton.Data#
+ * @returns {boolean} true iff the current node is null.
+ */
+_Data_['isNULL'] = function() {
+    return (_pn_data_is_null(this._data) > 0);
+};
+
+/**
+ * @method getBOOL
+ * @memberof! proton.Data#
+ * @returns {boolean} a boolean value if the current node is a boolean, returns
+ *          false otherwise.
+ */
+_Data_['getBOOL'] = function() {
+    return (_pn_data_get_bool(this._data) > 0);
+};
+
+/**
+ * @method getUBYTE
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is an unsigned byte, returns 0 otherwise.
+ */
+_Data_['getUBYTE'] = function() {
+    return _pn_data_get_ubyte(this._data) & 0xFF; // & 0xFF converts to unsigned;
+};
+
+/**
+ * @method getBYTE
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a signed byte, returns 0 otherwise.
+ */
+_Data_['getBYTE'] = function() {
+    return _pn_data_get_byte(this._data);
+};
+
+/**
+ * @method getUSHORT
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is an unsigned short, returns 0 otherwise.
+ */
+_Data_['getUSHORT'] = function() {
+    return _pn_data_get_ushort(this._data) & 0xFFFF; // & 0xFFFF converts to unsigned;
+};
+
+/**
+ * @method getSHORT
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a signed short, returns 0 otherwise.
+ */
+_Data_['getSHORT'] = function() {
+    return _pn_data_get_short(this._data);
+};
+
+/**
+ * @method getUINT
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is an unsigned int, returns 0 otherwise.
+ */
+_Data_['getUINT'] = function() {
+    var value = _pn_data_get_uint(this._data);
+    return (value > 0) ? value : 4294967296 + value; // 4294967296 == 2^32
+};
+
+/**
+ * @method getINT
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a signed int, returns 0 otherwise.
+ */
+_Data_['getINT'] = function() {
+    return _pn_data_get_int(this._data);
+};
+
+/**
+ * @method getCHAR
+ * @memberof! proton.Data#
+ * @returns {string} the character represented by the unicode value of the current node.
+ */
+_Data_['getCHAR'] = function() {
+    return String.fromCharCode(_pn_data_get_char(this._data));
+};
+
+/**
+ * Retrieve an unsigned long value. N.B. large values can suffer from a loss of
+ * precision as JavaScript numbers are restricted to 64 bit double values.
+ * @method getULONG
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Long} value if the current node is an unsigned long, returns 0 otherwise.
+ */
+_Data_['getULONG'] = function() {
+    var low = _pn_data_get_ulong(this._data);
+    var high = Runtime.getTempRet0();
+    var long = new Data.Long(low, high);
+    long = long.toNumber();
+    return (long >= 0) ? long : Data.Long.TWO_PWR_64_DBL_ + long;
+};
+
+/**
+ * Retrieve a signed long value. N.B. large values can suffer from a loss of
+ * precision as JavaScript numbers are restricted to 64 bit double values.
+ * @method getLONG
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Long} value if the current node is a signed long, returns 0 otherwise.
+ */
+_Data_['getLONG'] = function() {
+    // Getting the long is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to hold
+    // the 64 bit number and Data.Long.toNumber() to convert it back into a
+    // JavaScript number.
+    var low = _pn_data_get_long(this._data);
+    var high = Runtime.getTempRet0();
+    var long = new Data.Long(low, high);
+    long = long.toNumber();
+    return long;
+};
+
+/**
+ * @method getTIMESTAMP
+ * @memberof! proton.Data#
+ * @returns {Date} a native JavaScript Date instance representing the timestamp.
+ */
+_Data_['getTIMESTAMP'] = function() {
+    // Getting the timestamp is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to hold
+    // the 64 bit number and Data.Long.toNumber() to convert it back into a
+    // JavaScript number.
+    var low =  _pn_data_get_timestamp(this._data);
+    var high = Runtime.getTempRet0();
+    var long = new Data.Long(low, high);
+    long = long.toNumber();
+    return new Date(long);
+};
+
+/**
+ * Retrieves a  float value. N.B. converting between floats and doubles is imprecise
+ * so the resulting value might not quite be what you expect.
+ * @method getFLOAT
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a float, returns 0 otherwise.
+ */
+_Data_['getFLOAT'] = function() {
+    return _pn_data_get_float(this._data);
+};
+
+/**
+ * @method getDOUBLE
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a double, returns 0 otherwise.
+ */
+_Data_['getDOUBLE'] = function() {
+    return _pn_data_get_double(this._data);
+};
+
+/**
+ * @method getDECIMAL32
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a decimal32, returns 0 otherwise.
+ */
+_Data_['getDECIMAL32'] = function() {
+console.log("getDECIMAL32 not properly implemented yet");
+    return _pn_data_get_decimal32(this._data);
+};
+
+/**
+ * @method getDECIMAL64
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a decimal64, returns 0 otherwise.
+ */
+_Data_['getDECIMAL64'] = function() {
+console.log("getDECIMAL64 not properly implemented yet");
+    return _pn_data_get_decimal64(this._data);
+};
+
+/**
+ * @method getDECIMAL128
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is a decimal128, returns 0 otherwise.
+ */
+_Data_['getDECIMAL128'] = function() {
+console.log("getDECIMAL128 not properly implemented yet");
+    return _pn_data_get_decimal128(this._data);
+};
+
+/**
+ * @method getUUID
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Uuid} value if the current node is a UUID, returns null otherwise.
+ */
+_Data_['getUUID'] = function() {
+    var sp = Runtime.stackSave();
+
+    // Here's the quirky bit, pn_data_get_uuid actually returns pn_uuid_t
+    // *by value* but the low-level code handles this *by pointer* so we first
+    // need to allocate 16 bytes storage for pn_uuid_t on the emscripten stack
+    // and then we pass the pointer to that storage as the first parameter to the
+    // compiled pn_data_get_uuid.
+    var bytes = allocate(16, 'i8', ALLOC_STACK); // pn_uuid_t is 16 bytes.
+    _pn_data_get_uuid(bytes, this._data);
+
+    // Create a new UUID from the bytes
+    var uuid = new Data['Uuid'](bytes);
+
+    // Tidy up the memory that we allocated on emscripten's stack.
+    Runtime.stackRestore(sp);
+
+    return uuid;
+};
+
+/**
+ * @method getBINARY
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Binary} value if the current node is a Binary, returns null otherwise.
+ */
+_Data_['getBINARY'] = function() {
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_bytes bytes = pn_data_get_binary(data);
+
+    // Here's the quirky bit, pn_data_get_binary actually returns pn_bytes_t 
+    // *by value* but the low-level code handles this *by pointer* so we first
+    // need to allocate 8 bytes storage for {size, start} on the emscripten stack
+    // and then we pass the pointer to that storage as the first parameter to the
+    // compiled pn_data_get_binary.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_data_get_binary(bytes, this._data);
+
+    // The bytes variable is really of type pn_bytes_t* so we use emscripten's
+    // getValue() call to retrieve the size and then the start pointer.
+    var size  = getValue(bytes, 'i32');
+    var start = getValue(bytes + 4, '*');
+
+    // Create a proton.Data.Binary from the pn_bytes_t information.
+    var binary = new Data['Binary'](size, start);
+
+    // Tidy up the memory that we allocated on emscripten's stack.
+    Runtime.stackRestore(sp);
+
+    // If _decodeBinaryAsString is set return the stringified form of the Binary.
+    if (this._decodeBinaryAsString) {
+        return binary.toString();
+    } else {
+        return binary;
+    }
+};
+
+/**
+ * Gets a unicode String value from the current node.
+ * @method getSTRING
+ * @memberof! proton.Data#
+ * @returns {string} value if the current node is a String, returns "" otherwise.
+ */
+_Data_['getSTRING'] = function() {
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_bytes bytes = pn_data_get_string(data);
+
+    // Here's the quirky bit, pn_data_get_string actually returns pn_bytes_t 
+    // *by value* but the low-level code handles this *by pointer* so we first
+    // need to allocate 8 bytes storage for {size, start} on the emscripten stack
+    // and then we pass the pointer to that storage as the first parameter to the
+    // compiled pn_data_get_string.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_data_get_string(bytes, this._data);
+
+    // The bytes variable is really of type pn_bytes_t* so we use emscripten's
+    // getValue() call to retrieve the size and then the start pointer.
+    var size  = getValue(bytes, 'i32');
+    var start = getValue(bytes + 4, '*');
+
+    // Create a native JavaScript String from the pn_bytes_t information.
+    var string = Pointer_stringify(start, size);
+
+    // Tidy up the memory that we allocated on emscripten's stack.
+    Runtime.stackRestore(sp);
+
+    return string;
+};
+
+/**
+ * Gets a symbolic value. According to the AMQP 1.0 Specification Symbols are
+ * values from a constrained domain. Although the set of possible domains is
+ * open-ended, typically the both number and size of symbols in use for any
+ * given application will be small, e.g. small enough that it is reasonable to
+ * cache all the distinct values. Symbols are encoded as ASCII characters.
+ * @method getSYMBOL
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Symbol} value if the current node is a Symbol, returns "" otherwise.
+ */
+_Data_['getSYMBOL'] = function() {
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_bytes bytes = pn_data_get_symbol(data);
+
+    // Here's the quirky bit, pn_data_get_symbol actually returns pn_bytes_t 
+    // *by value* but the low-level code handles this *by pointer* so we first
+    // need to allocate 8 bytes storage for {size, start} on the emscripten stack
+    // and then we pass the pointer to that storage as the first parameter to the
+    // compiled pn_data_get_symbol.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_data_get_symbol(bytes, this._data);
+
+    // The bytes variable is really of type pn_bytes_t* so we use emscripten's
+    // getValue() call to retrieve the size and then the start pointer.
+    var size  = getValue(bytes, 'i32');
+    var start = getValue(bytes + 4, '*');
+
+    // Create a native JavaScript String from the pn_bytes_t information.
+    var string = Pointer_stringify(start, size);
+
+    // Tidy up the memory that we allocated on emscripten's stack.
+    Runtime.stackRestore(sp);
+
+    return new Data['Symbol'](string);
+};
+
+/**
+ * Performs a deep copy of the current {@link proton.Data} instance and returns it
+ * @method copy
+ * @memberof! proton.Data#
+ * @returns {proton.Data} a copy of the current {@link proton.Data} instance.
+ */
+_Data_['copy'] = function() {
+    var copy = new Data();
+    this._check(_pn_data_copy(copy._data, this._data));
+    return copy;
+};
+
+/**
+ * Format the encoded AMQP Data into a string representation and return it.
+ * @method format
+ * @memberof! proton.Data#
+ * @returns {string} a formatted string representation of the encoded Data.
+ */
+_Data_['format'] = function() {
+    var size = 1024; // Pass by reference variable - need to use setValue to initialise it.
+    while (true) {
+        setValue(size, size, 'i32'); // Set pass by reference variable.
+        var bytes = _malloc(size);   // Allocate storage from emscripten heap.
+        var err = _pn_data_format(this._data, bytes, size);
+        var size = getValue(size, 'i32'); // Dereference the real size value;
+
+        if (err === Module['Error']['OVERFLOW']) {
+            _free(bytes);
+            size *= 2;
+        } else {
+            var string = Pointer_stringify(bytes);
+            _free(bytes);
+            this._check(err)
+            return string;
+        }
+    }
+};
+
+/**
+ * Print the internal state of the {@link proton.Data} in human readable form.
+ * TODO. This seems to "crash" if compound nodes such as DESCRIBED, MAP or LIST
+ * are present in the tree, this is most likely a problem with the underlying C
+ * implementation as all the other navigation and format methods work - need to
+ * check by testing with some native C code.
+ * @method dump
+ * @memberof! proton.Data#
+ */
+_Data_['dump'] = function() {
+    _pn_data_dump(this._data);
+};
+
+/**
+ * Serialise a Native JavaScript Object into an AMQP Map.
+ * @method putMAP
+ * @memberof! proton.Data#
+ * @param {object} object the Native JavaScript Object that we wish to serialise.
+ */
+_Data_['putMAP'] = function(object) {
+    this['putMAPNODE']();
+    this['enter']();
+    for (var key in object) {
+        if (object.hasOwnProperty(key)) {
+            this['putObject'](key);
+            this['putObject'](object[key]);
+        }
+    }
+    this['exit']();
+};
+
+/**
+ * Deserialise from an AMQP Map into a Native JavaScript Object.
+ * @method getMAP
+ * @memberof! proton.Data#
+ * @returns {object} the deserialised Native JavaScript Object.
+ */
+_Data_['getMAP'] = function() {
+    if (this['enter']()) {
+        var result = {};
+        while (this['next']()) {
+            var key = this['getObject']();
+            var value = null;
+            if (this['next']()) {
+                value = this['getObject']();
+            }
+            result[key] = value;
+        }
+        this['exit']();
+        return result;
+    }
+};
+
+/**
+ * Serialise a Native JavaScript Array into an AMQP List.
+ * @method putLIST
+ * @memberof! proton.Data#
+ * @param {Array} array the Native JavaScript Array that we wish to serialise.
+ */
+_Data_['putLIST'] = function(array) {
+    this['putLISTNODE']();
+    this['enter']();
+    for (var i = 0, len = array.length; i < len; i++) {
+        this['putObject'](array[i]);
+    }
+    this['exit']();
+};
+
+/**
+ * Deserialise from an AMQP List into a Native JavaScript Array.
+ * @method getLIST
+ * @memberof! proton.Data#
+ * @returns {Array} the deserialised Native JavaScript Array.
+ */
+_Data_['getLIST'] = function() {
+    if (this['enter']()) {
+        var result = [];
+        while (this['next']()) {
+            result.push(this['getObject']());
+        }
+        this['exit']();
+        return result;
+    }
+};
+
+/**
+ * Serialise a proton.Data.Described into an AMQP Described.
+ * @method putDESCRIBED
+ * @memberof! proton.Data#
+ * @param {proton.Data.Described} d the proton.Data.Described that we wish to serialise.
+ */
+_Data_['putDESCRIBED'] = function(d) {
+    this['putDESCRIBEDNODE']();
+    this['enter']();
+    this['putObject'](d['descriptor']);
+    this['putObject'](d['value']);
+    this['exit']();
+};
+
+/**
+ * Deserialise from an AMQP Described into a proton.Data.Described.
+ * @method getDESCRIBED
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Described} the deserialised proton.Data.Described.
+ */
+_Data_['getDESCRIBED'] = function() {
+    if (this['enter']()) {
+        this['next']();
+        var descriptor = this['getObject']();
+        this['next']();
+        var value = this['getObject']();
+        this['exit']();
+        return new Data['Described'](value, descriptor);
+    }
+};
+
+/**
+ * Serialise a proton.Data.Array or JavaScript TypedArray into an AMQP Array.
+ * @method putARRAY
+ * @memberof! proton.Data#
+ * @param {object} a the proton.Data.Array or TypedArray that we wish to serialise.
+ */
+_Data_['putARRAY'] = function(a) {
+    var type = 1;
+    var descriptor = 'TypedArray';
+    var array = a;
+
+    if (a instanceof Data['Array']) { // Array is a proton.Data.Array
+        type = Data[a['type']]; // Find the integer type from its name string.
+        descriptor = a['descriptor'];
+        array = a['elements'];
+    } else { // Array is a Native JavaScript TypedArray so work out the right type.
+        if (a instanceof Int8Array) {
+            type = Data['BYTE'];
+        } else if (a instanceof Uint8Array || a instanceof Uint8ClampedArray) {
+            type = Data['UBYTE'];
+        } else if (a instanceof Int16Array) {
+            type = Data['SHORT'];
+        } else if (a instanceof Uint16Array) {
+            type = Data['USHORT'];
+        } else if (a instanceof Int32Array) {
+            type = Data['INT'];
+        } else if (a instanceof Uint32Array) {
+            type = Data['UINT'];
+        } else if (a instanceof Float32Array) {
+            type = Data['FLOAT'];
+        } else if (a instanceof Float64Array) {
+            type = Data['DOUBLE'];
+        }
+    }
+
+    var described = descriptor != null;
+
+    this['putARRAYNODE'](described, type);
+    this['enter']();
+    if (described) {
+        this['putObject'](descriptor);
+    }
+    var putter = 'put' + Data['TypeNames'][type];
+    for (var i = 0, len = array.length; i < len; i++) {
+        var value = array[i];
+        value = (value instanceof Data.TypedNumber) ? value.value : value;
+        this[putter](value);
+    }
+    this['exit']();
+};
+
+/**
+ * Deserialise from an AMQP Array into a proton.Data.Array.
+ * @method getARRAY
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Array} the deserialised proton.Data.Array.
+ */
+_Data_['getARRAY'] = function() {
+    var metadata = this['getARRAYNODE']();
+    var count = metadata['count'];
+    var described = metadata['described'];
+    var type = metadata['type'];
+
+    if (type === null) {
+        return null;
+    }
+
+    var elements = null;
+    if (typeof ArrayBuffer === 'function') {
+        if (type === Data['BYTE']) {
+            elements = new Int8Array(count);
+        } else if (type === Data['UBYTE']) {
+            elements = new Uint8Array(count);
+        } else if (type === Data['SHORT']) {
+            elements = new Int16Array(count);
+        } else if (type === Data['USHORT']) {
+            elements = new Uint16Array(count);
+        } else if (type === Data['INT']) {
+            elements = new Int32Array(count);
+        } else if (type === Data['UINT']) {
+            elements = new Uint32Array(count);
+        } else if (type === Data['FLOAT']) {
+            elements = new Float32Array(count);
+        } else if (type === Data['DOUBLE']) {
+            elements = new Float64Array(count);
+        } else {
+            elements = new Array(count);
+        }
+    } else {
+        elements = new Array(count);
+    }
+
+    if (this['enter']()) {
+        var descriptor; // Deliberately initialised as undefined not null.
+        if (described) {
+            this['next']();
+            descriptor = this['getObject']();
+        }
+
+        for (var i = 0; i < count; i++) {
+            this['next']();
+            elements[i] = this['getObject']();
+        }
+
+        this['exit']();
+        if (descriptor === 'TypedArray') {
+            return elements;
+        } else {
+            return new Data['Array'](type, elements, descriptor);
+        }
+    }
+};
+
+/**
+ * This method is the entry point for serialising native JavaScript types into
+ * AMQP types. In an ideal world there would be a nice clean one to one mapping
+ * and we could employ a look-up table but in practice the JavaScript type system
+ * doesn't really lend itself to that and we have to employ extra checks,
+ * heuristics and inferences.
+ * @method putObject
+ * @memberof! proton.Data#
+ * @param {object} obj the JavaScript Object or primitive to be serialised.
+ */
+_Data_['putObject'] = function(obj) {
+//console.log("Data.putObject " + obj);
+
+    if (obj == null) { // == Checks for null and undefined.
+        this['putNULL']();
+    } else if (Data.isString(obj)) {
+        var quoted = obj.match(/(['"])[^'"]*\1/);
+        if (quoted) { // If a quoted string extract the string inside the quotes.
+            obj = quoted[0].slice(1, -1);
+        }
+        this['putSTRING'](obj);
+    } else if (obj instanceof Date) {
+        this['putTIMESTAMP'](obj);
+    } else if (obj instanceof Data['Uuid']) {
+        this['putUUID'](obj);
+    } else if (obj instanceof Data['Binary']) {
+        this['putBINARY'](obj);
+    } else if (obj instanceof Data['Symbol']) {
+        this['putSYMBOL'](obj);
+    } else if (obj instanceof Data['Described']) {
+        this['putDESCRIBED'](obj);
+    } else if (obj instanceof Data['Array']) {
+        this['putARRAY'](obj);
+    } else if (obj.buffer && (typeof ArrayBuffer === 'function') && 
+               obj.buffer instanceof ArrayBuffer) {
+        this['putARRAY'](obj);
+    } else if (obj instanceof Data.TypedNumber) { // Dot notation used for "protected" inner class.
+        // Call the appropriate serialisation method based upon the numerical type.
+        this['put' + obj.type](obj.value);
+    } else if (Data.isNumber(obj)) {
+        /**
+         * This block encodes standard JavaScript numbers by making some inferences.
+         * Encoding JavaScript numbers is surprisingly complex and has several
+         * gotchas. The code here tries to do what the author believes is the
+         * most "intuitive" encoding of the native JavaScript Number. It first
+         * tries to identify if the number is an integer or floating point type
+         * by checking if the number modulo 1 is zero (i.e. if it has a remainder
+         * then it's a floating point type, which is encoded here as a double).
+         * If the number is an integer type a test is made to check if it is a
+         * 32 bit Int value. N.B. gotcha - JavaScript automagically coerces floating
+         * point numbers with a zero Fractional Part into an *exact* integer so
+         * numbers like 1.0, 100.0 etc. will be encoded as int or long here,
+         * which is unlikely to be what is wanted. There's no easy "transparent"
+         * way around this. The TypedNumber approach above allows applications
+         * to express more explicitly what is required, for example (1.0).float()
+         * (1).ubyte(), (5).long() etc.
+         */
+        if (obj % 1 === 0) {
+            if (obj === (obj|0)) { // the |0 coerces to a 32 bit value.
+                // 32 bit integer - encode as an INT.
+                this['putINT'](obj);
+            } else { // Longer than 32 bit - encode as a Long.
+                this['putLONG'](obj);
+            }
+        } else { // Floating point type - encode as a Double
+            this['putDOUBLE'](obj);
+        }
+    } else if (Data.isBoolean(obj)) {
+        this['putBOOL'](obj);
+    } else if (Data.isArray(obj)) { // Native JavaScript Array
+        this['putLIST'](obj);
+    } else {
+        this['putMAP'](obj);
+    }
+};
+
+/**
+ * @method getObject
+ * @memberof! proton.Data#
+ * @returns {object} the JavaScript Object or primitive being deserialised.
+ */
+_Data_['getObject'] = function() {
+    var type = Data['TypeNames'][this.type()];
+    type = type ? type : 'NULL';
+    var getter = 'get' + type;
+    return this[getter]();
+};
+
diff --git a/proton-c/bindings/javascript/error.js b/proton-c/bindings/javascript/error.js
new file mode 100644
index 0000000..4069bef
--- /dev/null
+++ b/proton-c/bindings/javascript/error.js
@@ -0,0 +1,172 @@
+/*
+ * 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.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                                   Status                                  */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Export Status Enum, avoiding minification.
+ * @enum
+ * @alias Status
+ * @memberof proton
+ */
+Module['Status'] = {
+    /** PN_STATUS_UNKNOWN */  'UNKNOWN':  0, // The tracker is unknown.
+    /** PN_STATUS_PENDING */  'PENDING':  1, // The message is in flight.
+                                             // For outgoing messages, use messenger.isBuffered()
+                                             // to see if it has been sent or not.
+    /** PN_STATUS_ACCEPTED */ 'ACCEPTED': 2, // The message was accepted.
+    /** PN_STATUS_REJECTED */ 'REJECTED': 3, // The message was rejected.
+    /** PN_STATUS_RELEASED */ 'RELEASED': 4, // The message was released.
+    /** PN_STATUS_MODIFIED */ 'MODIFIED': 5, // The message was modified.
+    /** PN_STATUS_ABORTED */  'ABORTED':  6, // The message was aborted.
+    /** PN_STATUS_SETTLED */  'SETTLED':  7  // The remote party has settled the message.
+};
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*                                   Error                                   */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Export Error Enum, avoiding minification.
+ * @enum
+ * @alias Error
+ * @memberof proton
+ */
+Module['Error'] = {
+    /** PN_EOS */        'EOS':        -1,
+    /** PN_ERR */        'ERR':        -2,
+    /** PN_OVERFLOW */   'OVERFLOW':   -3,
+    /** PN_UNDERFLOW */  'UNDERFLOW':  -4,
+    /** PN_STATE_ERR */  'STATE_ERR':  -5,
+    /** PN_ARG_ERR */    'ARG_ERR':    -6,
+    /** PN_TIMEOUT */    'TIMEOUT':    -7,
+    /** PN_INTR */       'INTR':       -8,
+    /** PN_INPROGRESS */ 'INPROGRESS': -9
+};
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*                               MessengerError                              */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Constructs a proton.MessengerError instance.
+ * @classdesc This class is a subclass of Error.
+ * @constructor proton.MessengerError
+ * @param {string} message the error message.
+ */
+Module['MessengerError'] = function(message) { // MessengerError constructor.
+    this.name = "MessengerError";
+    this.message = (message || "");
+};
+
+Module['MessengerError'].prototype = new Error();
+Module['MessengerError'].prototype.constructor = Module['MessengerError'];
+
+Module['MessengerError'].prototype.toString = function() {
+    return this.name + ': ' + this.message;
+};
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*                              SubscriptionError                            */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Constructs a proton.SubscriptionError instance.
+ * @classdesc This class is a subclass of MessengerError.
+ * @constructor proton.SubscriptionError
+ * @param {string} source the address that we want to subscribe to.
+ * @param {string} message the error message.
+ */
+Module['SubscriptionError'] = function(source, message) { // SubscriptionError constructor.
+    this.name = "SubscriptionError";
+    this.source = source;
+    this.message = (message || "");
+};
+
+Module['SubscriptionError'].prototype = new Module['MessengerError']();
+Module['SubscriptionError'].prototype.constructor = Module['SubscriptionError'];
+
+Module['SubscriptionError'].prototype.toString = function() {
+    return this.name + ': ' + this.source + ': ' + this.message;
+};
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*                                MessageError                               */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Constructs a proton.MessageError instance.
+ * @classdesc This class is a subclass of Error.
+ * @constructor proton.MessageError
+ * @param {string} message the error message.
+ */
+Module['MessageError'] = function(message) { // MessageError constructor.
+    this.name = "MessageError";
+    this.message = (message || "");
+};
+
+Module['MessageError'].prototype = new Error();
+Module['MessageError'].prototype.constructor = Module['MessageError'];
+
+Module['MessageError'].prototype.toString = function() {
+    return this.name + ': ' + this.message;
+};
+
+
+/*****************************************************************************/
+/*                                                                           */
+/*                                  DataError                                */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Constructs a proton.DataError instance.
+ * @classdesc This class is a subclass of Error.
+ * @constructor proton.DataError
+ * @param {string} message the error message.
+ */
+Module['DataError'] = function(message) { // DataError constructor.
+    this.name = "DataError";
+    this.message = (message || "");
+};
+
+Module['DataError'].prototype = new Error();
+Module['DataError'].prototype.constructor = Module['DataError'];
+
+Module['DataError'].prototype.toString = function() {
+    return this.name + ': ' + this.message;
+};
+
diff --git a/proton-c/bindings/javascript/message.js b/proton-c/bindings/javascript/message.js
new file mode 100644
index 0000000..564cc6e
--- /dev/null
+++ b/proton-c/bindings/javascript/message.js
@@ -0,0 +1,848 @@
+/*
+ * 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.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                                  Message                                  */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Constructs a proton.Message instance.
+ * @classdesc This class is a mutable holder of message content that may be used
+ * to generate and encode or decode and access AMQP formatted message data.
+ * @constructor proton.Message
+ * @property {object} instructions delivery instructions for the message.
+ * @property {object} annotations infrastructure defined message annotations.
+ * @property {object} properties application defined message properties.
+ * @property {object} body message body as a native JavaScript Object.
+ * @property {object} data message body as a proton.Data Object.
+ */
+Module['Message'] = function() { // Message Constructor.
+    this._message = _pn_message();
+    this._id = new Data(_pn_message_id(this._message));
+    this._correlationId = new Data(_pn_message_correlation_id(this._message));
+
+    // ************************* Public properties ****************************
+
+    this['instructions'] = null;
+    this['annotations'] = null;
+
+    // Intitialise with an empty Object so we can set properties in a natural way.
+    // message.properties.prop1 = "foo";
+    // message.properties.prop2 = "bar";
+    this['properties'] = {};
+
+    this['body'] = null;
+    this['data'] = null;
+};
+
+// Expose constructor as package scope variable to make internal calls less verbose.
+var Message = Module['Message'];
+
+// Expose prototype as a variable to make method declarations less verbose.
+var _Message_ = Message.prototype;
+
+// ************************** Class properties ********************************
+
+Message['DEFAULT_PRIORITY'] = 4; /** Default priority for messages.*/
+
+// ************************* Protected methods ********************************
+
+// We use the dot notation rather than associative array form for protected
+// methods so they are visible to this "package", but the Closure compiler will
+// minify and obfuscate names, effectively making a defacto "protected" method.
+
+/**
+ * This helper method checks the supplied error code, converts it into an
+ * exception and throws the exception. This method will try to use the message
+ * populated in pn_message_error(), if present, but if not it will fall
+ * back to using the basic error code rendering from pn_code().
+ * @param code the error code to check.
+ */
+_Message_._check = function(code) {
+    if (code < 0) {
+        var errno = this['getErrno']();
+        var message = errno ? this['getError']() : Pointer_stringify(_pn_code(code));
+
+        throw new Module['MessageError'](message);
+    } else {
+        return code;
+    }
+};
+
+/**
+ * Encode the Message prior to sending on the wire.
+ */
+_Message_._preEncode = function() {
+    // A Message Object may be reused so we create new Data instances and clear
+    // the state for them each time put() gets called.
+    var inst = new Data(_pn_message_instructions(this._message));
+    var ann = new Data(_pn_message_annotations(this._message));
+    var props = new Data(_pn_message_properties(this._message));
+    var body = new Data(_pn_message_body(this._message));
+
+    inst.clear();
+    if (this['instructions']) {
+        inst['putObject'](this['instructions']);
+    }
+
+    ann.clear();
+    if (this['annotations']) {
+        ann['putObject'](this['annotations']);
+    }
+
+    props.clear();
+    if (this['properties']) {
+        props['putObject'](this['properties']);
+    }
+
+    body.clear();
+    if (this['body']) {
+        var contentType = this['getContentType']();
+        if (contentType) {
+            var value = this['body'];
+            if (contentType === 'application/json' && JSON) { // Optionally encode body as JSON.
+                var json = JSON.stringify(value);
+                value = new Data['Binary'](json);
+            } else if (!(value instanceof Data['Binary'])) { // Construct a Binary from the body
+                value = new Data['Binary'](value);
+            }
+            // As content-type is set we send as an opaque AMQP data section.
+            this['setInferred'](true);
+            body['putBINARY'](value);
+        } else { // By default encode body using the native AMQP type system.
+            this['setInferred'](false);
+            body['putObject'](this['body']);
+        }
+    }
+};
+
+/**
+ * Decode the Message after receiving off the wire.
+ * @param {boolean} decodeBinaryAsString if set decode any AMQP Binary payload
+ *        objects as strings. This can be useful as the data in Binary objects
+ *        will be overwritten with subsequent calls to get, so they must be
+ *        explicitly copied. Needless to say it is only safe to set this flag if
+ *        you know that the data you are dealing with is actually a string, for
+ *        example C/C++ applications often seem to encode strings as AMQP binary,
+ *        a common cause of interoperability problems.
+ */
+_Message_._postDecode = function(decodeBinaryAsString) {
+    var inst = new Data(_pn_message_instructions(this._message));
+    var ann = new Data(_pn_message_annotations(this._message));
+    var props = new Data(_pn_message_properties(this._message));
+    var body = new Data(_pn_message_body(this._message), decodeBinaryAsString);
+
+    if (inst.next()) {
+        this['instructions'] = inst['getObject']();
+    } else {
+        this['instructions'] = {};
+    }
+
+    if (ann.next()) {
+        this['annotations'] = ann['getObject']();
+    } else {
+        this['annotations'] = {};
+    }
+
+    if (props.next()) {
+        this['properties'] = props['getObject']();
+    } else {
+        this['properties'] = {};
+    }
+
+    if (body.next()) {
+        this['data'] = body;
+        this['body'] = body['getObject']();
+        var contentType = this['getContentType']();
+        if (contentType) {
+            if (contentType === 'application/json' && JSON) {
+                var json = this['body'].toString(); // Convert Binary to String.
+                this['body'] = JSON.parse(json);
+            } else if (contentType.indexOf('text/') === 0) { // It's a text/* MIME type
+                this['body'] = this['body'].toString(); // Convert Binary to String.
+            }
+        }
+    } else {
+        this['data'] = null;
+        this['body'] = null;
+    }
+};
+
+// *************************** Public methods *********************************
+
+/**
+ * Free the Message.
+ * <p>
+ * N.B. This method has to be called explicitly in JavaScript as we can't
+ * intercept finalisers, so we need to remember to free before removing refs.
+ * @method free
+ * @memberof! proton.Message#
+ */
+_Message_['free'] = function() {
+    _pn_message_free(this._message);
+};
+
+/**
+ * @method getErrno
+ * @memberof! proton.Message#
+ * @returns {number the most recent error message code.
+ */
+_Message_['getErrno'] = function() {
+    return _pn_message_errno(this._message);
+};
+
+/**
+ * @method getError
+ * @memberof! proton.Message#
+ * @returns {string} the most recent error message as a String.
+ */
+_Message_['getError'] = function() {
+    return Pointer_stringify(_pn_error_text(_pn_message_error(this._message)));
+};
+
+/**
+ * Clears the contents of the Message. All fields will be reset to their default values.
+ * @method clear
+ * @memberof! proton.Message#
+ */
+_Message_['clear'] = function() {
+    _pn_message_clear(this._message);
+    this['instructions'] = null;
+    this['annotations'] = null;
+    this['properties'] = {};
+    this['body'] = null;
+    this['data'] = null;
+};
+
+/**
+ * Get the inferred flag for a message.
+ * <p>
+ * The inferred flag for a message indicates how the message content
+ * is encoded into AMQP sections. If inferred is true then binary and
+ * list values in the body of the message will be encoded as AMQP DATA
+ * and AMQP SEQUENCE sections, respectively. If inferred is false,
+ * then all values in the body of the message will be encoded as AMQP
+ * VALUE sections regardless of their type. Use
+ * {@link proton.Message.setInferred} to set the value.
+ * @method isInferred
+ * @memberof! proton.Message#
+ * @returns {boolean} true iff the inferred flag for the message is set.
+ */
+_Message_['isInferred'] = function() {
+    return (_pn_message_is_inferred(this._message) > 0);
+};
+
+/**
+ * Set the inferred flag for a message. See {@link proton.Message.isInferred} 
+ * for a description of what the inferred flag is.
+ * @method setInferred
+ * @memberof! proton.Message#
+ * @param {boolean} inferred the new value of the inferred flag.
+ */
+_Message_['setInferred'] = function(inferred) {
+    this._check(_pn_message_set_inferred(this._message, inferred));
+};
+
+/**
+ * Get the durable flag for a message.
+ * <p>
+ * The durable flag indicates that any parties taking responsibility
+ * for the message must durably store the content. Use
+ * {@link proton.Message.setDurable} to set the value.
+ * @method isDurable
+ * @memberof! proton.Message#
+ * @returns {boolean} true iff the durable flag for the message is set.
+ */
+_Message_['isDurable'] = function() {
+    return (_pn_message_is_durable(this._message) > 0);
+};
+
+/**
+ * Set the durable flag for a message. See {@link proton.Message.isDurable} 
+ * for a description of what the durable flag is.
+ * @method setDurable
+ * @memberof! proton.Message#
+ * @param {boolean} durable the new value of the durable flag.
+ */
+_Message_['setDurable'] = function(durable) {
+    this._check(_pn_message_set_durable(this._message, durable));
+};
+
+/**
+ * Get the priority for a message.
+ * <p>
+ * The priority of a message impacts ordering guarantees. Within a
+ * given ordered context, higher priority messages may jump ahead of
+ * lower priority messages. Priority range is 0..255
+ * @method getPriority
+ * @memberof! proton.Message#
+ * @returns {number} the priority of the Message.
+ */
+_Message_['getPriority'] = function() {
+    return _pn_message_get_priority(this._message) & 0xFF; // & 0xFF converts to unsigned.
+};
+
+/**
+ * Set the priority of the Message. See {@link proton.Message.getPriority}
+ * for details on message priority.
+ * @method setPriority
+ * @memberof! proton.Message#
+ * @param {number} priority the address we want to send the Message to.
+ */
+_Message_['setPriority'] = function(priority) {
+    this._check(_pn_message_set_priority(this._message, priority));
+};
+
+/**
+ * Get the ttl for a message.
+ * <p>
+ * The ttl for a message determines how long a message is considered
+ * live. When a message is held for retransmit, the ttl is
+ * decremented. Once the ttl reaches zero, the message is considered
+ * dead. Once a message is considered dead it may be dropped. Use
+ * {@link proton.Message.setTTL} to set the ttl for a message.
+ * @method getTTL
+ * @memberof! proton.Message#
+ * @returns {number} the ttl in milliseconds.
+ */
+_Message_['getTTL'] = function() {
+    return _pn_message_get_ttl(this._message);
+};
+
+/**
+ * Set the ttl for a message. See {@link proton.Message.getTTL}
+ * for a detailed description of message ttl.
+ * @method setTTL
+ * @memberof! proton.Message#
+ * @param {number} ttl the new value for the message ttl in milliseconds.
+ */
+_Message_['setTTL'] = function(ttl) {
+    this._check(_pn_message_set_ttl(this._message, ttl));
+};
+
+/**
+ * Get the first acquirer flag for a message.
+ * <p>
+ * When set to true, the first acquirer flag for a message indicates
+ * that the recipient of the message is the first recipient to acquire
+ * the message, i.e. there have been no failed delivery attempts to
+ * other acquirers. Note that this does not mean the message has not
+ * been delivered to, but not acquired, by other recipients.
+ * @method isFirstAcquirer
+ * @memberof! proton.Message#
+ * @returns {boolean} true iff the first acquirer flag for the message is set.
+ */
+_Message_['isFirstAcquirer'] = function() {
+    return (_pn_message_is_first_acquirer(this._message) > 0);
+};
+
+/**
+ * Set the first acquirer flag for a message. See {@link proton.Message.isFirstAcquirer} 
+ * for details on the first acquirer flag.
+ * @method setFirstAcquirer
+ * @memberof! proton.Message#
+ * @param {boolean} first the new value of the first acquirer flag.
+ */
+_Message_['setFirstAcquirer'] = function(first) {
+    this._check(_pn_message_set_first_acquirer(this._message, first));
+};
+
+/**
+ * Get the delivery count for a message.
+ * <p>
+ * The delivery count field tracks how many attempts have been made to
+ * deliver a message. Use {@link proton.Message.setDeliveryCount} to set
+ * the delivery count for a message.
+ * @method getDeliveryCount
+ * @memberof! proton.Message#
+ * @returns {number} the delivery count for the message.
+ */
+_Message_['getDeliveryCount'] = function() {
+    return _pn_message_get_delivery_count(this._message);
+};
+
+/**
+ * Set the delivery count for a message. See {@link proton.Message.getDeliveryCount}
+ * for details on what the delivery count means.
+ * @method setDeliveryCount
+ * @memberof! proton.Message#
+ * @param {number} count the new delivery count.
+ */
+_Message_['setDeliveryCount'] = function(count) {
+    this._check(_pn_message_set_delivery_count(this._message, count));
+};
+
+/**
+ * Get the id for a message.
+ * <p>
+ * The message id provides a globally unique identifier for a message.
+ * A message id can be an a string, an unsigned long, a uuid or a binary value.
+ * @method getID
+ * @memberof! proton.Message#
+ * @returns {(number|string|proton.Data.Long|proton.Data.Uuid|proton.Data.Binary)} the message id.
+ */
+_Message_['getID'] = function() {
+    return this._id['getObject']();
+};
+
+/**
+ * Set the id for a message. See {@link proton.Message.getID}
+ * for more details on the meaning of the message id. Note that only string,
+ * unsigned long, uuid, or binary values are permitted.
+ * @method setID
+ * @memberof! proton.Message#
+ * @param {(number|string|proton.Data.Long|proton.Data.Uuid|proton.Data.Binary)} id the
+ *        new value of the message id.
+ */
+_Message_['setID'] = function(id) {
+    this._id['rewind']();
+    if (Data.isNumber(id)) {
+        this._id['putULONG'](id);
+    } else {
+        this._id['putObject'](id);
+    }
+};
+
+/**
+ * Get the user id of the message creator.
+ * <p>
+ * The underlying raw data of the returned {@link proton.Data.Binary} will be
+ * valid until any one of the following operations occur:
+ * <pre>
+ *  - {@link proton.Message.free}
+ *  - {@link proton.Message.clear}
+ *  - {@link proton.Message.setUserID}
+ * </pre>
+ * @method getUserID
+ * @memberof! proton.Message#
+ * @returns {proton.Data.Binary} the message's user id.
+ */
+_Message_['getUserID'] = function() {
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_bytes_t bytes = pn_message_get_user_id(message);
+
+    // Here's the quirky bit, pn_message_get_user_id actually returns pn_bytes_t 
+    // *by value* but the low-level code handles this *by pointer* so we first
+    // need to allocate 8 bytes storage for {size, start} on the emscripten stack
+    // and then we pass the pointer to that storage as the first parameter to the
+    // compiled pn_message_get_user_id.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_message_get_user_id(bytes, this._message);
+
+    // The bytes variable is really of type pn_bytes_t* so we use emscripten's
+    // getValue() call to retrieve the size and then the start pointer.
+    var size  = getValue(bytes, 'i32');
+    var start = getValue(bytes + 4, '*');
+
+    // Create a proton.Data.Binary from the pn_bytes_t information.
+    var binary = new Data['Binary'](size, start);
+
+    // Tidy up the memory that we allocated on emscripten's stack.
+    Runtime.stackRestore(sp);
+
+    return binary;
+};
+
+/**
+ * Set the user id for a message. This method takes a {@link proton.Data.Binary}
+ * consuming the underlying raw data in the process. For convenience this method
+ * also accepts a {@link proton.Data.Uuid}, number or string, converting them to a
+ * Binary internally. N.B. getUserID always returns a {@link proton.Data.Binary}
+ * even if a string or {@link proton.Data.Uuid} has been passed to setUserID.
+ * @method setUserID
+ * @memberof! proton.Message#
+ * @param {(string|proton.Data.Uuid)} id the new user id for the message.
+ */
+_Message_['setUserID'] = function(id) {
+    // If the id parameter is a proton.Data.Binary use it otherwise create a Binary
+    // using the string form of the parameter that was passed.
+    id = (id instanceof Data['Binary']) ? id : new Data['Binary']('' + id);
+
+    var sp = Runtime.stackSave();
+    // The implementation here is a bit "quirky" due to some low-level details
+    // of the interaction between emscripten and LLVM and the use of pn_bytes.
+    // The JavaScript code below is basically a binding to:
+    //
+    // pn_message_set_user_id(message, pn_bytes(id.size, id.start));
+
+    // Here's the quirky bit, pn_bytes actually returns pn_bytes_t *by value* but
+    // the low-level code handles this *by pointer* so we first need to allocate
+    // 8 bytes storage for {size, start} on the emscripten stack and then we
+    // pass the pointer to that storage as the first parameter to the pn_bytes.
+    var bytes = allocate(8, 'i8', ALLOC_STACK);
+    _pn_bytes(bytes, id.size, id.start);
+
+    // The compiled pn_message_set_user_id takes the pn_bytes_t by reference not value.
+    this._check(_pn_message_set_user_id(this._message, bytes));
+
+    // After calling _pn_message_set_user_id the underlying Message object "owns" the
+    // binary data, so we can call free on the proton.Data.Binary instance to
+    // release any storage it has acquired back to the emscripten heap.
+    id['free']();
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Get the address for a message.
+ * @method getAddress
+ * @memberof! proton.Message#
+ * @returns {string} the address of the Message.
+ */
+_Message_['getAddress'] = function() {
+    return Pointer_stringify(_pn_message_get_address(this._message));
+};
+
+/**
+ * Set the address of the Message.
+ * @method setAddress
+ * @memberof! proton.Message#
+ * @param {string} address the address we want to send the Message to.
+ */
+_Message_['setAddress'] = function(address) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_message_set_address(this._message, allocate(intArrayFromString(address), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Get the subject for a message.
+ * @method getSubject
+ * @memberof! proton.Message#
+ * @returns {string} the subject of the Message.
+ */
+_Message_['getSubject'] = function() {
+    return Pointer_stringify(_pn_message_get_subject(this._message));
+};
+
+/**
+ * Set the subject of the Message.
+ * @method setSubject
+ * @memberof! proton.Message#
+ * @param {string} subject the subject we want to set for the Message.
+ */
+_Message_['setSubject'] = function(subject) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_message_set_subject(this._message, allocate(intArrayFromString(subject), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Get the reply to for a message.
+ * @method getReplyTo
+ * @memberof! proton.Message#
+ * @returns {string} the reply to of the Message.
+ */
+_Message_['getReplyTo'] = function() {
+    return Pointer_stringify(_pn_message_get_reply_to(this._message));
+};
+
+/**
+ * Set the reply to for a message.
+ * @method setReplyTo
+ * @memberof! proton.Message#
+ * @param {string} reply the reply to we want to set for the Message.
+ */
+_Message_['setReplyTo'] = function(reply) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_message_set_reply_to(this._message, allocate(intArrayFromString(reply), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Get the correlation id for a message.
+ * <p>
+ * A correlation id can be an a string, an unsigned long, a uuid or a binary value.
+ * @method getCorrelationID
+ * @memberof! proton.Message#
+ * @returns {(number|string|proton.Data.Long|proton.Data.Uuid|proton.Data.Binary)} the message id.
+ */
+_Message_['getCorrelationID'] = function() {
+    return this._correlationId['getObject']();
+};
+
+/**
+ * Set the correlation id for a message. See {@link proton.Message.getCorrelationID}
+ * for more details on the meaning of the correlation id. Note that only string,
+ * unsigned long, uuid, or binary values are permitted.
+ * @method setCorrelationID
+ * @memberof! proton.Message#
+ * @param {(number|string|proton.Data.Long|proton.Data.Uuid|proton.Data.Binary)} id the
+ *        new value of the correlation id.
+ */
+_Message_['setCorrelationID'] = function(id) {
+    this._correlationId['rewind']();
+    if (Data.isNumber(id)) {
+        this._correlationId['putULONG'](id);
+    } else {
+        this._correlationId['putObject'](id);
+    }
+};
+
+/**
+ * Get the content type for a message.
+ * @method getContentType
+ * @memberof! proton.Message#
+ * @returns {string} the content type of the Message.
+ */
+_Message_['getContentType'] = function() {
+    return Pointer_stringify(_pn_message_get_content_type(this._message));
+};
+
+/**
+ * Set the content type for a message.
+ * @method setContentType
+ * @memberof! proton.Message#
+ * @param {string} type the content type we want to set for the Message.
+ */
+_Message_['setContentType'] = function(type) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_message_set_content_type(this._message, allocate(intArrayFromString(type), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Get the content encoding for a message.
+ * @method getContentEncoding
+ * @memberof! proton.Message#
+ * @returns {string} the content encoding of the Message.
+ */
+_Message_['getContentEncoding'] = function() {
+    return Pointer_stringify(_pn_message_get_content_encoding(this._message));
+};
+
+/**
+ * Set the content encoding for a message.
+ * @method setContentEncoding
+ * @memberof! proton.Message#
+ * @param {string} encoding the content encoding we want to set for the Message.
+ */
+_Message_['setContentEncoding'] = function(encoding) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_message_set_content_encoding(this._message, allocate(intArrayFromString(encoding), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Get the expiry time for a message.
+ * A zero value for the expiry time indicates that the message will
+ * never expire. This is the default value.
+ * @method getExpiryTime
+ * @memberof! proton.Message#
+ * @returns {Date} the expiry time for the message.
+ */
+_Message_['getExpiryTime'] = function() {
+    // Getting the timestamp is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to hold
+    // the 64 bit number and Data.Long.toNumber() to convert it back into a
+    // JavaScript number.
+    var low =  _pn_message_get_expiry_time(this._message);
+    var high = Runtime.getTempRet0();
+    var long = new Data.Long(low, high);
+    long = long.toNumber();
+    return new Date(long);
+};
+
+/**
+ * Set the expiry time for a message.
+ * @method setExpiryTime
+ * @memberof! proton.Message#
+ * @param {(number|Date)} time the new expiry time for the message.
+ */
+_Message_['setExpiryTime'] = function(time) {
+    // Note that a timestamp is a 64 bit number so we have to use a proton.Data.Long.
+    var timestamp = Data.Long.fromNumber(time.valueOf());
+    this._check(_pn_message_set_expiry_time(this._message, timestamp.getLowBitsUnsigned(), timestamp.getHighBits()));
+};
+
+/**
+ * Get the creation time for a message.
+ * A zero value for the creation time indicates that the creation time
+ * has not been set. This is the default value.
+ * @method getCreationTime
+ * @memberof! proton.Message#
+ * @returns {Date} the creation time for the message.
+ */
+_Message_['getCreationTime'] = function() {
+    // Getting the timestamp is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to hold
+    // the 64 bit number and Data.Long.toNumber() to convert it back into a
+    // JavaScript number.
+    var low =  _pn_message_get_creation_time(this._message);
+    var high = Runtime.getTempRet0();
+    var long = new Data.Long(low, high);
+    long = long.toNumber();
+    return new Date(long);
+};
+
+/**
+ * Set the creation time for a message.
+ * @method setCreationTime
+ * @memberof! proton.Message#
+ * @param {(number|Date)} time the new creation time for the message.
+ */
+_Message_['setCreationTime'] = function(time) {
+    // Note that a timestamp is a 64 bit number so we have to use a proton.Data.Long.
+    var timestamp = Data.Long.fromNumber(time.valueOf());
+    this._check(_pn_message_set_creation_time(this._message, timestamp.getLowBitsUnsigned(), timestamp.getHighBits()));
+};
+
+/**
+ * Get the group id for a message.
+ * @method getGroupID
+ * @memberof! proton.Message#
+ * @returns {string} the group id of the Message.
+ */
+_Message_['getGroupID'] = function() {
+    return Pointer_stringify(_pn_message_get_group_id(this._message));
+};
+
+/**
+ * Set the group id for a message.
+ * @method setGroupID
+ * @memberof! proton.Message#
+ * @param {string} id the group id we want to set for the Message.
+ */
+_Message_['setGroupID'] = function(id) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_message_set_group_id(this._message, allocate(intArrayFromString(id), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Get the group sequence for a message.
+ * <p>
+ * The group sequence of a message identifies the relative ordering of
+ * messages within a group. The default value for the group sequence
+ * of a message is zero.
+ * @method getGroupSequence
+ * @memberof! proton.Message#
+ * @returns {number} the group sequence for the message.
+ */
+_Message_['getGroupSequence'] = function() {
+    return _pn_message_get_group_sequence(this._message);
+};
+
+/**
+ * Set the group sequence for a message. See {@link proton.Message.getGroupSequence}
+ * for details on what the group sequence means.
+ * @method setGroupSequence
+ * @memberof! proton.Message#
+ * @param {number} n the new group sequence for the message.
+ */
+_Message_['setGroupSequence'] = function(n) {
+    this._check(_pn_message_set_group_sequence(this._message, n));
+};
+
+/**
+ * Get the reply to group id for a message.
+ * @method getReplyToGroupID
+ * @memberof! proton.Message#
+ * @returns {string} the reply to group id of the Message.
+ */
+_Message_['getReplyToGroupID'] = function() {
+    return Pointer_stringify(_pn_message_get_reply_to_group_id(this._message));
+};
+
+/**
+ * Set the reply to group id for a message.
+ * @method setReplyToGroupID
+ * @memberof! proton.Message#
+ * @param {string} id the reply to group id we want to set for the Message.
+ */
+_Message_['setReplyToGroupID'] = function(id) {
+    var sp = Runtime.stackSave();
+    this._check(_pn_message_set_reply_to_group_id(this._message, allocate(intArrayFromString(id), 'i8', ALLOC_STACK)));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * The following methods are marked as deprecated and are not implemented.
+ * pn_message_get_format()
+ * pn_message_set_format()
+ * pn_message_load()
+ * pn_message_load_data()
+ * pn_message_load_text()
+ * pn_message_load_amqp()
+ * pn_message_load_json()
+ * pn_message_save()
+ * pn_message_save_data()
+ * pn_message_save_text()
+ * pn_message_save_amqp()
+ * pn_message_save_json()
+ * pn_message_data()
+ */
+
+/**
+ * Return a Binary representation of the message encoded in AMQP format. N.B. the
+ * returned {@link proton.Data.Binary} "owns" the underlying raw data and is thus
+ * responsible for freeing it or passing it to a method that consumes a Binary
+ * such as {@link proton.Message.decode}.
+ * @method encode
+ * @memberof! proton.Message#
+ * @returns {proton.Data.Binary} a representation of the message encoded in AMQP format.
+ */
+_Message_['encode'] = function() {
+    this._preEncode();
+    var size = 1024;
+    while (true) {
+        setValue(size, size, 'i32'); // Set pass by reference variable.
+        var bytes = _malloc(size);   // Allocate storage from emscripten heap.
+        var err = _pn_message_encode(this._message, bytes, size);
+        var size = getValue(size, 'i32'); // Dereference the real size value;
+
+        if (err === Module['Error']['OVERFLOW']) {
+            _free(bytes);
+            size *= 2;
+        } else if (err >= 0) {
+            return new Data['Binary'](size, bytes);
+        } else {
+            _free(bytes);
+            this._check(err);
+            return;
+        }
+    }
+};
+
+/**
+ * Decodes and loads the message content from supplied Binary AMQP data  N.B. 
+ * this method "consumes" data from a {@link proton.Data.Binary} in other words
+ * it takes responsibility for the underlying data and frees the raw data from
+ * the Binary.
+ * @method decode
+ * @memberof! proton.Message#
+ * @param {proton.Data.Binary} encoded the AMQP encoded binary message.
+ */
+_Message_['decode'] = function(encoded) {
+    var err = _pn_message_decode(this._message, encoded.start, encoded.size);
+    encoded['free'](); // Free the original Binary.
+    if (err >= 0) {
+        this._postDecode();
+    }
+    this._check(err);
+};
+
diff --git a/proton-c/bindings/javascript/messenger.js b/proton-c/bindings/javascript/messenger.js
new file mode 100644
index 0000000..e2f4418
--- /dev/null
+++ b/proton-c/bindings/javascript/messenger.js
@@ -0,0 +1,810 @@
+/*
+ * 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.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                                 Messenger                                 */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Constructs a proton.Messenger instance giving it an (optional) name. If name
+ * is supplied that will be used as the name of the Messenger, otherwise a UUID
+ * will be used. The Messenger is initialised to non-blocking mode as it makes
+ * little sense to have blocking behaviour in a JavaScript implementation.
+ * @classdesc The {@link proton.Messenger} class defines a high level interface for sending
+ * and receiving {@link proton.Message}. Every {@link proton.Messenger} contains a
+ * single logical queue of incoming messages and a single logical queue
+ * of outgoing messages. These messages in these queues may be destined
+ * for, or originate from, a variety of addresses.
+ * <p>
+ * The messenger interface is single-threaded.
+ * <pre>
+ * Address Syntax
+ * ==============
+ * </pre>
+ * An address has the following form:
+ * <pre>
+ *   [ amqp[s]:// ] [user[:password]@] domain [/[name]]
+ * </pre>
+ * Where domain can be one of:
+ * <pre>
+ *   host | host:port | ip | ip:port | name
+ * </pre>
+ * The following are valid examples of addresses:
+ * <pre>
+ *  - example.org
+ *  - example.org:1234
+ *  - amqp://example.org
+ *  - amqps://example.org
+ *  - example.org/incoming
+ *  - amqps://example.org/outgoing
+ *  - amqps://fred:trustno1@example.org
+ *  - 127.0.0.1:1234
+ *  - amqps://127.0.0.1:1234
+ *
+ * Sending & Receiving Messages
+ * ============================
+ * </pre>
+ * The {@link proton.Messenger} class works in conjuction with the {@link proton.Message} class.
+ * The {@link proton.Message} class is a mutable holder of message content.
+ * <p>
+ * The put method copies its Message to the outgoing queue, and may
+ * send queued messages if it can do so without blocking.  
+ * <pre>
+ *   var message = new proton.Message();
+ *   for (var i = 0; i < 3; i++) {
+ *      message.setAddress("amqp://host/queue");
+ *      message.setSubject = ("Hello World " + i);
+ *      messenger.put(message);
+ *   }
+ * </pre>
+ * Similarly, the recv method receives messages into the incoming
+ * queue. It may receive fewer than the requested number. The get method pops the
+ * eldest Message off the incoming queue and copies it into the Message
+ * object that you supply.
+ * <pre>
+ *   var message = new proton.Message();
+ *   messenger.recv(10);
+ *   while (messenger.incoming() > 0) {
+ *      messenger.get(message);
+ *      console.log(message.getSubject());
+ *   }
+ *   Hello World 0
+ *   Hello World 1
+ *   Hello World 2
+ * </pre>
+ *
+ * @constructor proton.Messenger
+ * @param {string} name the name of this Messenger instance.
+ */
+Module['Messenger'] = function(name) { // Messenger Constructor.
+    /**
+     * The emscripten idiom below is used in a number of places in the JavaScript
+     * bindings to map JavaScript Strings to C style strings. ALLOC_STACK will
+     * increase the stack and place the item there. When the stack is next restored
+     * (by calling Runtime.stackRestore()), that memory will be automatically
+     * freed. In C code compiled by emscripten saving and restoring of the stack
+     * is automatic, but if we want to us ALLOC_STACK from native JavaScript we
+     * need to explicitly save and restore the stack using Runtime.stackSave()
+     * and Runtime.stackRestore() or we will leak emscripten heap memory.
+     * See https://github.com/kripken/emscripten/wiki/Interacting-with-code
+     * The _pn_messenger constructor copies the char* passed to it.
+     */
+    var sp = Runtime.stackSave();
+    this._messenger = _pn_messenger(name ? allocate(intArrayFromString(name), 'i8', ALLOC_STACK) : 0);
+    Runtime.stackRestore(sp);
+
+    /**
+     * Initiate Messenger non-blocking mode. For JavaScript we make this the
+     * default behaviour and don't export this method because JavaScript is
+     * fundamentally an asynchronous non-blocking execution environment.
+     */
+    _pn_messenger_set_blocking(this._messenger, false);
+
+    // Subscriptions that haven't yet completed, used for managing subscribe events.
+    this._pendingSubscriptions = [];
+
+    // Used in the Event registration mechanism (in the 'on' and 'emit' methods).
+    this._callbacks = {};
+
+    // This call ensures that the emscripten network callback functions are initialised.
+    Module.EventDispatch.registerMessenger(this);
+};
+
+Module['Messenger'].PN_CUMULATIVE = 0x1; // Protected Class attribute.
+
+// Expose prototype as a variable to make method declarations less verbose.
+var _Messenger_ = Module['Messenger'].prototype;
+
+// ************************* Protected methods ********************************
+
+// We use the dot notation rather than associative array form for protected
+// methods so they are visible to this "package", but the Closure compiler will
+// minify and obfuscate names, effectively making a defacto "protected" method.
+
+/**
+ * This helper method checks the supplied error code, converts it into an
+ * exception and throws the exception. This method will try to use the message
+ * populated in pn_messenger_error(), if present, but if not it will fall
+ * back to using the basic error code rendering from pn_code().
+ * @param {number} code the error code to check.
+ */
+_Messenger_._check = function(code) {
+    if (code < 0 && code !== Module['Error']['INPROGRESS']) {
+        var errno = this['getErrno']();
+        var message = errno ? this['getError']() : Pointer_stringify(_pn_code(code));
+        if (message !== 'PN_TIMEOUT') {
+            if (this._callbacks['error']) {
+console.log("emitting " + message);
+                this._emit('error', new Module['MessengerError'](message));
+            } else {
+console.log("throwing " + message);
+                throw new Module['MessengerError'](message);
+            }
+        }
+    }
+
+    return code;
+};
+
+/**
+ * Invokes the callbacks registered for a specified event.
+ * @method _emit
+ * @memberof! proton.Messenger#
+ * @param event {string} the event we want to emit.
+ * @param param {object} the parameter we'd like to pass to the event callback.
+ */
+_Messenger_._emit = function(event, param) {
+    var callbacks = this._callbacks[event];
+    if (callbacks) {
+        for (var i = 0; i < callbacks.length; i++) {
+            var callback = callbacks[i];
+            if ('function' === typeof callback) {
+                callback.call(this, param);
+            }
+        }
+    }
+};
+
+/**
+ * Checks any pending subscriptions and when a source address becomes available
+ * emit a subscription event passing the Subscription that triggered the event.
+ * Note that this doesn't seem to work for listen/bind style subscriptions,
+ * that is to say subscriptions of the form amqp://~0.0.0.0, don't know why?
+ * As a workaround the subscribe call emits a subscription event immediately for
+ * peer subscriptions to the local Messenger, this *should* be OK.
+ */
+_Messenger_._checkSubscriptions = function() {
+    // Check for completed subscriptions, and emit subscribe event.
+    var subscriptions = this._pendingSubscriptions;
+    if (subscriptions.length) {
+        var pending = []; // Array of any subscriptions that remain pending.
+        for (var j = 0; j < subscriptions.length; j++) {
+            subscription = subscriptions[j];
+            if (subscription['getAddress']()) {
+                this._emit('subscription', subscription);
+            } else {
+                pending.push(subscription);
+            }
+        }
+        this._pendingSubscriptions = pending;
+    }
+};
+
+
+// *************************** Public methods *****************************
+
+/**
+ * N.B. The following methods are not exported by the JavaScript Messenger
+ * binding for reasons described below.
+ *
+ * For these methods it is expected that security would be implemented via
+ * a secure WebSocket. TODO what happens if we decide to implement TCP sockets
+ * via Node.js net library. If we do that we may want to compile OpenSSL
+ * using emscripten and include these methods.
+ * pn_messenger_set_certificate()
+ * pn_messenger_get_certificate()
+ * pn_messenger_set_private_key()
+ * pn_messenger_get_private_key()
+ * pn_messenger_set_password()
+ * pn_messenger_get_password()
+ * pn_messenger_set_trusted_certificates()
+ * pn_messenger_get_trusted_certificates()
+ *
+ * For these methods the implementation is fairly meaningless because JavaScript
+ * is a fundamentally asynchronous non-blocking environment.
+ * pn_messenger_set_timeout()
+ * pn_messenger_set_blocking()
+ * pn_messenger_interrupt()
+ * pn_messenger_send() // Not sure if this is useful in JavaScript.
+ */
+
+/**
+ * Registers a listener callback for a specified event.
+ * @method on
+ * @memberof! proton.Messenger#
+ * @param {string} event the event we want to listen for.
+ * @param {function} callback the callback function to be registered for the specified event.
+ */
+_Messenger_['on'] = function(event, callback) {
+    if ('function' === typeof callback) {
+        if (!this._callbacks[event]) {
+            this._callbacks[event] = [];
+        }
+
+        this._callbacks[event].push(callback);
+    }
+};
+
+/**
+ * Removes a listener callback for a specified event.
+ * @method removeListener
+ * @memberof! proton.Messenger#
+ * @param {string} event the event we want to detach from.
+ * @param {function} callback the callback function to be removed for the specified event.
+ *        if no callback is specified all callbacks are removed for the event.
+ */
+_Messenger_['removeListener'] = function(event, callback) {
+    if (callback) {
+        var callbacks = this._callbacks[event];
+        if ('function' === typeof callback && callbacks) {
+            // Search for the specified callback.
+            for (var i = 0; i < callbacks.length; i++) {
+                if (callback === callbacks[i]) {
+                    // If we find the specified callback, delete it and return.
+                    callbacks.splice(i, 1);
+                    return;
+                }
+            }
+        }
+    } else {
+        // If we call remove with no callback specified we remove all callbacks.
+        delete this._callbacks[event];
+    }
+};
+
+/**
+ * Retrieves the name of a Messenger.
+ * @method getName
+ * @memberof! proton.Messenger#
+ * @returns {string} the name of the messenger.
+ */
+_Messenger_['getName'] = function() {
+    return Pointer_stringify(_pn_messenger_name(this._messenger));
+};
+
+/**
+ * Retrieves the timeout for a Messenger.
+ * @method getTimeout
+ * @memberof! proton.Messenger#
+ * @returns {number} zero because JavaScript is fundamentally non-blocking.
+ */
+_Messenger_['getTimeout'] = function() {
+    return 0;
+};
+
+/**
+ * Accessor for messenger blocking mode.
+ * @method isBlocking
+ * @memberof! proton.Messenger#
+ * @returns {boolean} false because JavaScript is fundamentally non-blocking.
+ */
+_Messenger_['isBlocking'] = function() {
+    return false;
+};
+
+/**
+ * Free the Messenger. This will close all connections that are managed
+ * by the Messenger. Call the stop method before destroying the Messenger.
+ * <p>
+ * N.B. This method has to be called explicitly in JavaScript as we can't
+ * intercept finalisers, so we need to remember to free before removing refs.
+ * @method free
+ * @memberof! proton.Messenger#
+ */
+_Messenger_['free'] = function() {
+    // This call ensures that the emscripten network callback functions are removed.
+    Module.EventDispatch.unregisterMessenger(this);
+    _pn_messenger_free(this._messenger);
+};
+
+/**
+ * @method getErrno
+ * @memberof! proton.Messenger#
+ * @returns {number} the most recent error message code.
+ */
+_Messenger_['getErrno'] = function() {
+    return _pn_messenger_errno(this._messenger);
+};
+
+/**
+ * @method getError
+ * @memberof! proton.Messenger#
+ * @returns {string} the most recent error message as a String.
+ */
+_Messenger_['getError'] = function() {
+    return Pointer_stringify(_pn_error_text(_pn_messenger_error(this._messenger)));
+};
+
+/**
+ * Returns the size of the outgoing window that was set with setOutgoingWindow.
+ * The default is 0.
+ * @method getOutgoingWindow
+ * @memberof! proton.Messenger#
+ * @returns {number} the outgoing window size.
+ */
+_Messenger_['getOutgoingWindow'] = function() {
+    return _pn_messenger_get_outgoing_window(this._messenger);
+};
+
+/**
+ * Sets the outgoing tracking window for the Messenger. The Messenger will
+ * track the remote status of this many outgoing deliveries after calling
+ * send. Defaults to zero.
+ * <p>
+ * A Message enters this window when you call put() with the Message.
+ * If your outgoing window size is n, and you call put() n+1 times, status
+ * information will no longer be available for the first Message.
+ * @method setOutgoingWindow
+ * @memberof! proton.Messenger#
+ * @param {number} window the size of the tracking window in messages.
+ */
+_Messenger_['setOutgoingWindow'] = function(window) {
+    _pn_messenger_set_outgoing_window(this._messenger, window);
+};
+
+/**
+ * Returns the size of the incoming window that was set with setIncomingWindow.
+ * The default is 0.
+ * @method getIncomingWindow
+ * @memberof! proton.Messenger#
+ * @returns {number} the incoming window size.
+ */
+_Messenger_['getIncomingWindow'] = function() {
+    return _pn_messenger_get_incoming_window(this._messenger);
+};
+
+/**
+ * Sets the incoming tracking window for the Messenger. The Messenger will
+ * track the remote status of this many incoming deliveries after calling
+ * send. Defaults to zero.
+ * <p>
+ * Messages enter this window only when you take them into your application
+ * using get(). If your incoming window size is n, and you get() n+1 messages
+ * without explicitly accepting or rejecting the oldest message, then the
+ * Message that passes beyond the edge of the incoming window will be assigned
+ * the default disposition of its link.
+ * @method setIncomingWindow
+ * @memberof! proton.Messenger#
+ * @param {number} window the size of the tracking window in messages.
+ */
+_Messenger_['setIncomingWindow'] = function(window) {
+    _pn_messenger_set_incoming_window(this._messenger, window);
+};
+
+/**
+ * Currently a no-op placeholder. For future compatibility, do not send or
+ * recv messages before starting the Messenger.
+ * @method start
+ * @memberof! proton.Messenger#
+ */
+_Messenger_['start'] = function() {
+    this._check(_pn_messenger_start(this._messenger));
+};
+
+/**
+ * Transitions the Messenger to an inactive state. An inactive Messenger
+ * will not send or receive messages from its internal queues. A Messenger
+ * should be stopped before being discarded to ensure a clean shutdown
+ * handshake occurs on any internally managed connections.
+ * <p>
+ * The Messenger may require some time to stop if it is busy, and in that
+ * case will return {@link proton.Error.INPROGRESS}. In that case, call isStopped
+ * to see if it has fully stopped.
+ * @method stop
+ * @memberof! proton.Messenger#
+ */
+_Messenger_['stop'] = function() {
+    _pn_messenger_stop(this._messenger);
+};
+
+/**
+ * Returns true iff a Messenger is in the stopped state.
+ * @method isStopped
+ * @memberof! proton.Messenger#
+ * @returns {boolean} true iff a Messenger is in the stopped state.
+ */
+_Messenger_['isStopped'] = function() {
+    return (_pn_messenger_stopped(this._messenger) > 0);
+};
+
+/**
+ * Subscribes the Messenger to messages originating from the
+ * specified source. The source is an address as specified in the
+ * Messenger introduction with the following addition. If the
+ * domain portion of the address begins with the '~' character, the
+ * Messenger will interpret the domain as host/port, bind to it,
+ * and listen for incoming messages. For example "~0.0.0.0",
+ * "amqp://~0.0.0.0", and "amqps://~0.0.0.0" will all bind to any
+ * local interface and listen for incoming messages with the last
+ * variant only permitting incoming SSL connections.
+ * @method subscribe
+ * @memberof! proton.Messenger#
+ * @param {string} source the source address we're subscribing to.
+ * @returns {Subscription} a subscription.
+ */
+_Messenger_['subscribe'] = function(source) {
+    if (!source) {
+        this._emit('error', new Module['SubscriptionError'](source, 'CONNECTION ERROR: Address not specified'));
+    } else {
+        return Module.EventDispatch.subscribe(this, source);
+    }
+};
+
+/**
+ * Places the content contained in the message onto the outgoing queue
+ * of the Messenger. This method will never block, however it will send any
+ * unblocked Messages in the outgoing queue immediately and leave any blocked
+ * Messages remaining in the outgoing queue. The outgoing property may be
+ * used to check the depth of the outgoing queue.
+ * <p>
+ * When the content in a given Message object is copied to the outgoing
+ * message queue, you may then modify or discard the Message object
+ * without having any impact on the content in the outgoing queue.
+ * <p>
+ * This method returns an outgoing tracker for the Message.  The tracker
+ * can be used to determine the delivery status of the Message.
+ * @method put
+ * @memberof! proton.Messenger#
+ * @param {proton.Message} message a Message to send.
+ * @param {boolean} flush if this is set true or is undefined then messages are
+ *        flushed (this is the default). If explicitly set to false then messages
+ *        may not be sent immediately and might require an explicit call to work().
+ *        This may be used to "batch up" messages and *may* be more efficient.
+ * @returns {proton.Data.Long} a tracker.
+ */
+_Messenger_['put'] = function(message, flush) {
+    flush = flush === false ? false : true; // Defaults to true if not explicitly specified.
+    message._preEncode();
+    this._check(_pn_messenger_put(this._messenger, message._message));
+
+    if (flush) {
+        Module.EventDispatch.flush();
+    }
+
+    // Getting the tracker is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
+    // low/high pair around to methods that require a tracker.
+    var low = _pn_messenger_outgoing_tracker(this._messenger);
+    var high = Runtime.getTempRet0();
+    return new Data.Long(low, high);
+};
+
+/**
+ * Gets the last known remote state of the delivery associated with the given tracker.
+ * @method status
+ * @memberof! proton.Messenger#
+ * @param {proton.Data.Long} tracker the tracker whose status is to be retrieved.
+ * @returns {proton.Status} one of None, PENDING, REJECTED, or ACCEPTED.
+ */
+_Messenger_['status'] = function(tracker) {
+    if (tracker == null) { // Use == not === to check for both null and undefined.
+        var low = _pn_messenger_outgoing_tracker(this._messenger);
+        var high = Runtime.getTempRet0();
+        tracker = new Data.Long(low, high);
+    }
+
+    return _pn_messenger_status(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits());
+};
+
+/**
+ * Checks if the delivery associated with the given tracker is still waiting to be sent.
+ * @method isBuffered
+ * @memberof! proton.Messenger#
+ * @param {proton.Data.Long} tracker the tracker identifying the delivery.
+ * @returns {boolean} true if delivery is still buffered.
+ */
+_Messenger_['isBuffered'] = function(tracker) {
+    if (tracker == null) { // Use == not === to check for both null and undefined.
+        var low = _pn_messenger_outgoing_tracker(this._messenger);
+        var high = Runtime.getTempRet0();
+        tracker = new Data.Long(low, high);
+    }
+
+    return (_pn_messenger_buffered(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits()) > 0);
+};
+
+/**
+ * Frees a Messenger from tracking the status associated with a given tracker.
+ * If you don't supply a tracker, all outgoing messages up to the most recent
+ * will be settled.
+ * @method settle
+ * @memberof! proton.Messenger#
+ * @param {proton.Data.Long} tracker the tracker identifying the delivery.
+ */
+_Messenger_['settle'] = function(tracker) {
+    // Getting the tracker is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
+    // low/high pair around to methods that require a tracker.
+    var flags = 0;
+    if (tracker == null) { // Use == not === to check for both null and undefined.
+        var low = _pn_messenger_outgoing_tracker(this._messenger);
+        var high = Runtime.getTempRet0();
+        tracker = new Data.Long(low, high);
+        flags = Module['Messenger'].PN_CUMULATIVE;
+    }
+
+    _pn_messenger_settle(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits(), flags);
+};
+
+/**
+ * Sends or receives any outstanding messages queued for a Messenger.
+ * For JavaScript the only timeout that makes sense is 0 (do not block).
+ * This method may also do I/O work other than sending and receiving messages.
+ * For example, closing connections after messenger.stop() has been called.
+ * @method work
+ * @memberof! proton.Messenger#
+ * @returns {boolean} true if there is work still to do, false otherwise.
+ */
+_Messenger_['work'] = function() {
+    return (this._check(_pn_messenger_work(this._messenger, 0)) > 0);
+};
+
+/**
+ * Receives up to limit messages into the incoming queue.  If no value for limit
+ * is supplied, this call will receive as many messages as it can buffer internally.
+ * @method recv
+ * @memberof! proton.Messenger#
+ * @param {number} limit the maximum number of messages to receive or -1 to to receive
+ *        as many messages as it can buffer internally.
+ */
+_Messenger_['recv'] = function(limit) {
+    _pn_messenger_recv(this._messenger, (limit ? limit : -1));
+};
+
+/**
+ * Returns the capacity of the incoming message queue of messenger. Note this
+ * count does not include those messages already available on the incoming queue.
+ * @method receiving
+ * @memberof! proton.Messenger#
+ * @returns {number} the message queue capacity.
+ */
+_Messenger_['receiving'] = function() {
+    return _pn_messenger_receiving(this._messenger);
+};
+
+/**
+ * Moves the message from the head of the incoming message queue into the
+ * supplied message object. Any content in the message will be overwritten.
+ * <p>
+ * A tracker for the incoming Message is returned. The tracker can later be
+ * used to communicate your acceptance or rejection of the Message.
+ * @method get
+ * @memberof! proton.Messenger#
+ * @param {proton.Message} message the destination message object. If no Message
+ *        object is supplied, the Message popped from the head of the queue is discarded.
+ * @param {boolean} decodeBinaryAsString if set decode any AMQP Binary payload
+ *        objects as strings. This can be useful as the data in Binary objects
+ *        will be overwritten with subsequent calls to get, so they must be
+ *        explicitly copied. Needless to say it is only safe to set this flag if
+ *        you know that the data you are dealing with is actually a string, for
+ *        example C/C++ applications often seem to encode strings as AMQP binary,
+ *        a common cause of interoperability problems.
+ * @returns {proton.Data.Long} a tracker for the incoming Message.
+ */
+_Messenger_['get'] = function(message, decodeBinaryAsString) {
+    var impl = null;
+    if (message) {
+        impl = message._message;
+    }
+
+    _pn_messenger_get(this._messenger, impl);
+
+    if (message) {
+        message._postDecode(decodeBinaryAsString);
+    }
+
+    // Getting the tracker is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
+    // low/high pair around to methods that require a tracker.
+    var low = _pn_messenger_incoming_tracker(this._messenger);
+    var high = Runtime.getTempRet0();
+    return new Data.Long(low, high);
+};
+
+/**
+ * Returns the Subscription of the Message returned by the most recent call
+ * to get, or null if pn_messenger_get has not yet been called.
+ * @method incomingSubscription
+ * @memberof! proton.Messenger#
+ * @returns {Subscription} a Subscription or null if get has never been called
+ *          for this Messenger.
+ */
+_Messenger_['incomingSubscription'] = function() {
+    var subscription = _pn_messenger_incoming_subscription(this._messenger);
+    if (subscription) {
+        return new Subscription(subscription);
+    } else {
+        return null;
+    }
+};
+
+/**
+ * Signal the sender that you have acted on the Message pointed to by the tracker.
+ * If no tracker is supplied, then all messages that have been returned by the
+ * get method are accepted, except those that have already been auto-settled
+ * by passing beyond your incoming window size.
+ * @method accept
+ * @memberof! proton.Messenger#
+ * @param {proton.Data.Long} tracker the tracker identifying the delivery.
+ */
+_Messenger_['accept'] = function(tracker) {
+    // Getting the tracker is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
+    // low/high pair around to methods that require a tracker.
+    var flags = 0;
+    if (tracker == null) { // Use == not === to check for both null and undefined.
+        var low = _pn_messenger_incoming_tracker(this._messenger);
+        var high = Runtime.getTempRet0();
+        tracker = new Data.Long(low, high);
+        flags = Module['Messenger'].PN_CUMULATIVE;
+    }
+
+    this._check(_pn_messenger_accept(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits(), flags));
+};
+
+/**
+ * Rejects the Message indicated by the tracker.  If no tracker is supplied,
+ * all messages that have been returned by the get method are rejected, except
+ * those already auto-settled by passing beyond your outgoing window size.
+ * @method reject
+ * @memberof! proton.Messenger#
+ * @param {proton.Data.Long} tracker the tracker identifying the delivery.
+ */
+_Messenger_['reject'] = function(tracker) {
+    // Getting the tracker is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to pass the
+    // low/high pair around to methods that require a tracker.
+    var flags = 0;
+    if (tracker == null) { // Use == not === to check for both null and undefined.
+        var low = _pn_messenger_incoming_tracker(this._messenger);
+        var high = Runtime.getTempRet0();
+        tracker = new Data.Long(low, high);
+        flags = Module['Messenger'].PN_CUMULATIVE;
+    }
+
+    this._check(_pn_messenger_reject(this._messenger, tracker.getLowBitsUnsigned(), tracker.getHighBits(), flags));
+};
+
+/**
+ * Returns the number of messages in the outgoing message queue of a messenger.
+ * @method outgoing
+ * @memberof! proton.Messenger#
+ * @returns {number} the outgoing queue depth.
+ */
+_Messenger_['outgoing'] = function() {
+    return _pn_messenger_outgoing(this._messenger);
+};
+
+/**
+ * Returns the number of messages in the incoming message queue of a messenger.
+ * @method incoming
+ * @memberof! proton.Messenger#
+ * @returns {number} the incoming queue depth.
+ */
+_Messenger_['incoming'] = function() {
+    return _pn_messenger_incoming(this._messenger);
+};
+
+/**
+ * Adds a routing rule to a Messenger's internal routing table.
+ * <p>
+ * The route method may be used to influence how a messenger will internally treat
+ * a given address or class of addresses. Every call to the route method will
+ * result in messenger appending a routing rule to its internal routing table.
+ * <p>
+ * Whenever a message is presented to a messenger for delivery, it will match the
+ * address of this message against the set of routing rules in order. The first
+ * rule to match will be triggered, and instead of routing based on the address
+ * presented in the message, the messenger will route based on the address supplied
+ * in the rule.
+ * <p>
+ * The pattern matching syntax supports two types of matches, a '' will match any
+ * character except a '/', and a '*' will match any character including a '/'.
+ * <p>
+ * A routing address is specified as a normal AMQP address, however it may
+ * additionally use substitution variables from the pattern match that triggered
+ * the rule.
+ * <p>
+ * Any message sent to "foo" will be routed to "amqp://foo.com":
+ * <pre>
+ * route("foo", "amqp://foo.com");
+ * </pre>
+ * Any message sent to "foobar" will be routed to "amqp://foo.com/bar":
+ * <pre>
+ * route("foobar", "amqp://foo.com/bar");
+ * </pre>
+ * Any message sent to bar/<path> will be routed to the corresponding path within
+ * the amqp://bar.com domain:
+ * <pre>
+ * route("bar/*", "amqp://bar.com/$1");
+ * </pre>
+ * Supply credentials for foo.com:
+ * <pre>
+ * route("amqp://foo.com/*", "amqp://user:password@foo.com/$1");
+ * </pre>
+ * Supply credentials for all domains:
+ * <pre>
+ * route("amqp://*", "amqp://user:password@$1");
+ * </pre>
+ * Route all addresses through a single proxy while preserving the original destination:
+ * <pre>
+ * route("amqp://%/*", "amqp://user:password@proxy/$1/$2");
+ * </pre>
+ * Route any address through a single broker:
+ * <pre>
+ * route("*", "amqp://user:password@broker/$1");
+ * </pre>
+ * @method route
+ * @memberof! proton.Messenger#
+ * @param {string} pattern a glob pattern to select messages.
+ * @param {string} address an address indicating outgoing address rewrite.
+ */
+_Messenger_['route'] = function(pattern, address) {
+    var sp = Runtime.stackSave();
+    _pn_messenger_route(this._messenger,
+                        allocate(intArrayFromString(pattern), 'i8', ALLOC_STACK),
+                        allocate(intArrayFromString(address), 'i8', ALLOC_STACK));
+    Runtime.stackRestore(sp);
+};
+
+/**
+ * Rewrite message addresses prior to transmission.
+ * <p>
+ * Similar to route(), except that the destination of the Message is determined
+ * before the message address is rewritten.
+ * <p>
+ * The outgoing address is only rewritten after routing has been finalized. If
+ * a message has an outgoing address of "amqp://0.0.0.0:5678", and a rewriting
+ * rule that changes its outgoing address to "foo", it will still arrive at the
+ * peer that is listening on "amqp://0.0.0.0:5678", but when it arrives there,
+ * the receiver will see its outgoing address as "foo".
+ * <p>
+ * The default rewrite rule removes username and password from addresses
+ * before they are transmitted.
+ * @method rewrite
+ * @memberof! proton.Messenger#
+ * @param {string} pattern a glob pattern to select messages.
+ * @param {string} address an address indicating outgoing address rewrite.
+ */
+_Messenger_['rewrite'] = function(pattern, address) {
+    var sp = Runtime.stackSave();
+    _pn_messenger_rewrite(this._messenger,
+                          allocate(intArrayFromString(pattern), 'i8', ALLOC_STACK),
+                          allocate(intArrayFromString(address), 'i8', ALLOC_STACK));
+    Runtime.stackRestore(sp);
+};
+
diff --git a/proton-c/bindings/javascript/module.js b/proton-c/bindings/javascript/module.js
new file mode 100644
index 0000000..b755f59
--- /dev/null
+++ b/proton-c/bindings/javascript/module.js
@@ -0,0 +1,426 @@
+/*
+ * 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.
+ *
+ */
+
+/**
+ * This file defines the Module Object which provides a namespace around the Proton
+ * Messenger API. The Module object is used extensively by the emscripten runtime,
+ * however for convenience it is exported with the name "proton" and not "Module".
+ * <p>
+ * The emscripten compiled proton-c code and the JavaScript binding code will be 
+ * minified by the Closure compiler, so all comments will be stripped from the
+ * actual library.
+ * <p>
+ * This JavaScript wrapper provides a somewhat more idiomatic object oriented
+ * interface which abstracts the low-level emscripten based implementation details
+ * from client code. Any similarities to the Proton Python binding are deliberate.
+ * @file
+ */
+
+/**
+ * The Module Object is exported by emscripten for all execution platforms, we
+ * use it as a namespace to allow us to selectively export only what we wish to
+ * be publicly visible from this package/module, which is wrapped in a closure.
+ * <p>
+ * Internally the binding code uses the associative array form for declaring
+ * exported properties to prevent the Closure compiler from minifying e.g.
+ * <pre>Module['Messenger'] = ...</pre>
+ * Exported Objects can however be used in client code using a more convenient
+ * and obvious proton namespace, e.g.:
+ * <pre>
+ * var proton = require('qpid-proton');
+ * var messenger = new proton.Messenger();
+ * var message = new proton.Message();
+ * ...
+ * </pre>
+ * The core part of this library is actually proton-c compiled into JavaScript.
+ * In order to provide C style memory management (malloc/free) emscripten uses
+ * a "virtual heap", which is actually a pre-allocated ArrayBuffer. The size of
+ * this virtual heap is set as part of the runtime initialisation and cannot be
+ * changed subsequently (the default size is 16*1024*1024 = 16777216).
+ * <p>
+ * Applications can specify the size of virtual heap that they require via the
+ * global variable PROTON_TOTAL_MEMORY, this must be set <b>before</b> the library is
+ * loaded e.g. in Node.js an application would do:
+ * <pre>
+ * PROTON_TOTAL_MEMORY = 50000000; // Note no var - it needs to be global.
+ * var proton = require('qpid-proton');
+ * ...
+ * </pre>
+ * A browser based application would do:
+ * <pre>
+ * &lt;script type="text/javascript"&gt;PROTON_TOTAL_MEMORY = 50000000;&lt;/script&gt;
+ * &lt;script type="text/javascript" src="proton.js">&lt;/script&gt;
+ * </pre>
+ * If the global variable PROTON_TOTAL_MEMORY has been set by the application this
+ * will result in the emscripten heap getting set to the next multiple of
+ * 16777216 above PROTON_TOTAL_MEMORY.
+ * <p>
+ * The global variable PROTON_TOTAL_STACK may be used in a similar way to increase
+ * the stack size from its default of 5*1024*1024 = 5242880. It is worth noting
+ * that Strings are allocated on the stack, so you may need this if you end up
+ * wanting to send very large strings.
+ * @namespace proton
+ */
+var Module = {};
+
+if (typeof global === 'object') { // If Node.js
+    if (global['PROTON_TOTAL_MEMORY']) {
+        Module['TOTAL_MEMORY'] = global['PROTON_TOTAL_MEMORY'];
+    }
+    if (global['PROTON_TOTAL_STACK']) {
+        Module['TOTAL_STACK'] = global['PROTON_TOTAL_STACK'];
+    }
+} else if (typeof window === 'object') { // If browser
+    if (window['PROTON_TOTAL_MEMORY']) {
+        Module['TOTAL_MEMORY'] = window['PROTON_TOTAL_MEMORY'];
+    }
+    if (window['PROTON_TOTAL_STACK']) {
+        Module['TOTAL_STACK'] = window['PROTON_TOTAL_STACK'];
+    }
+}
+
+/*****************************************************************************/
+/*                                                                           */
+/*                               EventDispatch                               */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * EventDispatch is a Singleton class that allows callbacks to be registered,
+ * which will get triggered by the emscripten WebSocket network callbacks.
+ * Clients of Messenger will register callbacks by calling:
+ * <pre>
+ * messenger.on('error', &lt;callback function&gt;);
+ * messenger.on('work', &lt;callback function&gt;);
+ * messenger.on('subscription', &lt;callback function&gt;);
+ * </pre>
+ * EventDispatch supports callback registration from multiple Messenger instances.
+ * The client callbacks will actually be called when a given messenger has work
+ * available or a WebSocket close has been occurred.
+ * <p>
+ * The approach implemented here allows the registered callbacks to follow a
+ * similar pattern to _process_incoming and _process_outgoing in async.py
+ * @constructor proton.EventDispatch
+ */
+Module.EventDispatch = new function() { // Note the use of new to create a Singleton.
+    var POLLIN  = 0x001;
+    var POLLOUT = 0x004;
+    var _error = null;
+    var _messengers = {};  // Keyed by name.
+    var _selectables = {}; // Keyed by file descriptor.
+
+    var _initialise = function() {
+        /**
+         * Initialises the emscripten network callback functions. This needs
+         * to be done the first time we call registerMessenger rather than
+         * when we create the Singleton because emscripten's socket filesystem
+         * has to be mounted before can listen for any of these events.
+         */
+        Module['websocket']['on']('open', _pump);
+        Module['websocket']['on']('connection', _pump);
+        Module['websocket']['on']('message', _pump);
+        Module['websocket']['on']('close', _closeHandler);
+        Module['websocket']['on']('error', _errorHandler);
+
+        /**
+         * For Node.js the network code uses the ws WebSocket library, see
+         * https://github.com/einaros/ws. The following is a "Monkey Patch"
+         * that fixes a problem with Receiver.js where it wasn't checking if
+         * an Object was null before accessing its properties, so it was
+         * possible to see errors like:
+         * TypeError: Cannot read property 'fragmentedOperation' of null
+         * at Receiver.endPacket (.....node_modules/ws/lib/Receiver.js:224:18)
+         * This problem is generally seen in Server code after messenger.stop()
+         * I *think* that the underlying issue is actually because ws calls
+         * cleanup directly rather than pushing it onto the event loop so the
+         * this.state stuff gets cleared before the endPacket method is called.
+         * This fix simply interposes a check to avoid calling endPacket if
+         * the state has been cleared (i.e. the WebSocket has been closed).
+         */
+        if (ENVIRONMENT_IS_NODE) {
+            try {
+                var ws = require('ws');
+                // Array notation to stop Closure compiler minifying properties we need.
+                ws['Receiver'].prototype['originalEndPacket'] = ws['Receiver'].prototype['endPacket'];
+                ws['Receiver'].prototype['endPacket'] = function() {
+                    if (this['state']) {
+                        this['originalEndPacket']();
+                    }
+                };
+            } catch (e) {
+                console.error("Failed to apply Monkey Patch to ws WebSocket library");
+            }
+        }
+
+        _initialise = function() {}; // After first call replace with null function.
+    };
+
+    /**
+     * Messenger error handling can be a bit inconsistent and in several places
+     * rather than returning an error code or setting an error it simply writes
+     * to fprintf. This is something of a Monkey Patch that replaces the emscripten
+     * library fprintf call with one that checks the message and sets a variable
+     * if the message is an ERROR. TODO At some point hopefully Dominic Evans'
+     * patch on Jira PROTON-571 will render this code redundant.
+     */
+    _fprintf = function(stream, format, varargs) {
+        var array = __formatString(format, varargs);
+        array.pop(); // Remove the trailing \n
+        var string = intArrayToString(array); // Convert to native JavaScript string.
+        if (string.indexOf('ERROR') === -1) { // If not an ERROR just log the message.
+            console.log(string);
+        } else {
+            _error = string;
+        }
+    };
+
+    /**
+     * This method iterates through all registered Messengers and retrieves any
+     * pending selectables, which are stored in a _selectables map keyed by fd.
+     */
+    var _updateSelectables = function() {
+        var sel = 0;
+        var fd = -1;
+        for (var name in _messengers) {
+            var messenger = _messengers[name];
+            while ((sel = _pn_messenger_selectable(messenger._messenger))) {
+                fd = _pn_selectable_fd(sel);
+                // Only register valid selectables, otherwise free them.
+                if (fd === -1) {
+                    _pn_selectable_free(sel);
+                } else {
+                    _selectables[fd] = {messenger: messenger, selectable: sel};
+                }
+            }
+        }
+        return fd; // Return the most recently added selector's file descriptor.
+    };
+
+    /**
+     * Continually pump data while there's still work to do.
+     */
+    var _pump = function() {
+        while (_pumpOnce());
+    };
+
+    /**
+     * This method more or less follows the pattern of the pump_once method from
+     * class Pump in tests/python/proton_tests/messenger.py. It looks a little
+     * different because the select/poll implemented here uses some low-level
+     * emscripten internals (stream = FS.getStream(fd), sock = stream.node.sock,
+     * mask = sock.sock_ops.poll(sock)). We use the internals so we don't have
+     * to massage from file descriptors into the C style poll interface.
+     */
+    var _pumpOnce = function() {
+        _updateSelectables();
+
+        var count = 0;
+        for (var fd in _selectables) {
+            var selectable = _selectables[fd];
+            var sel = selectable.selectable;
+            var terminal = _pn_selectable_is_terminal(sel);
+            if (terminal) {
+                _pn_selectable_free(sel);
+                delete _selectables[fd];
+            } else {
+                var stream = FS.getStream(fd);
+                if (stream) {
+                    var sock = stream.node.sock;
+                    if (sock.sock_ops.poll) {
+                        var mask = sock.sock_ops.poll(sock); // Low-level poll call.
+                        if (mask) {
+                            var messenger = selectable.messenger;
+                            var capacity = _pn_selectable_capacity(sel) > 0;
+                            var pending = _pn_selectable_pending(sel) > 0;
+
+                            if ((mask & POLLIN) && capacity) {
+//console.log("- readable fd = " + fd + ", capacity = " + _pn_selectable_capacity(sel));
+                                _error = null; // May get set by _pn_selectable_readable.
+                                _pn_selectable_readable(sel);
+                                count++; // Should this be inside the test for _error? Don't know.
+                                var errno = messenger['getErrno']();
+                                _error = errno ? messenger['getError']() : _error;
+                                if (_error) {
+                                    _errorHandler([fd, 0, _error]);
+                                } else {
+                                    // Don't send work event if it's a listen socket.
+                                    if (!sock.server) {
+                                        messenger._checkSubscriptions();
+                                        messenger._emit('work');
+                                    }
+                                }
+                            }
+                            if ((mask & POLLOUT) && pending) {
+//console.log("- writeable fd = " + fd + ", pending = " + _pn_selectable_pending(sel));
+                                _pn_selectable_writable(sel);
+                                //TODO looks like this block isn't needed. Need to
+                                //check with a test-case that writes data as fast as
+                                //it can. If not needed then delete.
+                                /*
+                                count++;
+                                // Check _selectables again in case the call to
+                                // _pn_selectable_writable caused a socket close.
+                                if (_selectables[fd]) {
+                                    messenger._checkSubscriptions();
+                                    messenger._emit('work');
+                                }
+                                */
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return count;
+    };
+
+    /**
+     * Handler for the emscripten socket close event.
+     */
+    var _closeHandler = function(fd) {
+        var selectable = _selectables[fd];
+        if (selectable) {
+            // Close and remove the selectable.
+            var sel = selectable.selectable;
+            _pn_selectable_free(sel); // This closes the underlying socket too.
+            delete _selectables[fd];
+
+            var messenger = selectable.messenger;
+            messenger._emit('work');
+        }
+    };
+
+    /**
+     * Handler for the emscripten socket error event.
+     */
+    var _errorHandler = function(error) {
+        var fd = error[0];
+        var message = error[2];
+
+        _updateSelectables();
+
+        var selectable = _selectables[fd];
+        if (selectable) {
+            // Close and remove the selectable.
+            var sel = selectable.selectable;
+            _pn_selectable_free(sel); // This closes the underlying socket too.
+            delete _selectables[fd];
+
+            var messenger = selectable.messenger;
+
+            // Remove any pending Subscriptions whose fd matches the error fd.
+            var subscriptions = messenger._pendingSubscriptions;
+            for (var i = 0; i < subscriptions.length; i++) {
+                subscription = subscriptions[i];
+                // Use == not === as we don't care if fd is a number or a string.
+                if (subscription.fd == fd) {
+                    messenger._pendingSubscriptions.splice(i, 1);
+                    if (message.indexOf('EHOSTUNREACH:') === 0) {
+                        message = 'CONNECTION ERROR (' + subscription.source + '): bind: Address already in use';
+                    }
+                    messenger._emit('error', new Module['SubscriptionError'](subscription.source, message));
+                    return;
+                }
+            }
+
+            messenger._emit('error', new Module['MessengerError'](message));
+        }
+    };
+
+    /**
+     * Flush any data that has been written by the Messenger put() method.
+     * @method flush
+     */
+    this.flush = function() {
+        _pump();
+    };
+
+    /**
+     * Subscribe to a specified source address.
+     * <p>
+     * This method is delegated to by the subscribe method of {@link proton.Messenger}.
+     * We delegate to EventDispatch because we create Subscription objects that
+     * contain some additional information (such as file descriptors) which are
+     * only available to EventDispatch and we don't really want to expose to the
+     * wider API. This low-level information is mainly used for error handling
+     * which is itself encapsulated in EventDispatch.
+     * @method subscribe
+     * @memberof! proton.EventDispatch#
+     * @param {proton.Messenger} messenger the Messenger instance that this
+     *        subscription relates to.
+     * @param {string} source the address that we'd like to subscribe to.
+     */
+    this.subscribe = function(messenger, source) {
+        // First update selectables before subscribing so we can work out the
+        // Subscription fd (which will be the listen file descriptor).
+        _updateSelectables();
+        var sp = Runtime.stackSave();
+        var subscription = _pn_messenger_subscribe(messenger._messenger,
+                                                   allocate(intArrayFromString(source), 'i8', ALLOC_STACK));
+        Runtime.stackRestore(sp);
+        var fd = _updateSelectables();
+
+        subscription = new Subscription(subscription, source, fd);
+        messenger._pendingSubscriptions.push(subscription);
+
+        // For passive subscriptions emit a subscription event (almost) immediately,
+        // otherwise defer until the address has been resolved remotely.
+        if (subscription.passive) {
+            // We briefly delay the call to checkSubscriptions because it is possible
+            // for passive subscriptions to fail if another process is bound to the
+            // port specified in the subscription.
+            var check = function() {messenger._checkSubscriptions();};
+            setTimeout(check, 10);
+        }
+
+        return subscription;
+    };
+
+    /**
+     * Register the specified Messenger as being interested in network events.
+     * @method registerMessenger
+     * @memberof! proton.EventDispatch#
+     * @param {proton.Messenger} messenger the Messenger instance we want to
+     *        register to receive network events.
+     */
+    this.registerMessenger = function(messenger) {
+        _initialise();
+
+        var name = messenger['getName']();
+        _messengers[name] = messenger;
+
+        // Set the Messenger "passive" as we are supplying our own event loop here.
+        _pn_messenger_set_passive(messenger._messenger, true);
+    };
+
+    /**
+     * Unregister the specified Messenger from interest in network events.
+     * @method unregisterMessenger
+     * @memberof! proton.EventDispatch#
+     * @param {proton.Messenger} messenger the Messenger instance we want to
+     *        unregister from receiving network events.
+     */
+    this.unregisterMessenger = function(messenger) {
+        var name = messenger['getName']();
+        delete _messengers[name];
+    };
+};
+
diff --git a/proton-c/bindings/javascript/qpid-proton/LICENSE b/proton-c/bindings/javascript/qpid-proton/LICENSE
new file mode 100644
index 0000000..6b0b127
--- /dev/null
+++ b/proton-c/bindings/javascript/qpid-proton/LICENSE
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+
diff --git a/proton-c/bindings/javascript/qpid-proton/README.md b/proton-c/bindings/javascript/qpid-proton/README.md
new file mode 100644
index 0000000..db026c7
--- /dev/null
+++ b/proton-c/bindings/javascript/qpid-proton/README.md
@@ -0,0 +1,4 @@
+qpid-proton
+-----------
+
+apache qpid proton messenger AMQP 1.0 library
diff --git a/proton-c/bindings/javascript/qpid-proton/lib/.gitignore b/proton-c/bindings/javascript/qpid-proton/lib/.gitignore
new file mode 100644
index 0000000..2b1f291
--- /dev/null
+++ b/proton-c/bindings/javascript/qpid-proton/lib/.gitignore
@@ -0,0 +1,21 @@
+#
+# 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.
+#
+
+# Currently empty .gitignore
+# Used to ensure git creates the otherwise empty directory
diff --git a/proton-c/bindings/javascript/qpid-proton/package.json b/proton-c/bindings/javascript/qpid-proton/package.json
new file mode 100644
index 0000000..ffc5ebe
--- /dev/null
+++ b/proton-c/bindings/javascript/qpid-proton/package.json
@@ -0,0 +1,11 @@
+{
+    "name" : "qpid-proton",
+    "version": "0.7.0",
+    "description": "apache qpid proton messenger AMQP 1.0 library",
+    "repository": {
+        "type": "svn",
+        "url": "https://svn.apache.org/repos/asf/qpid/proton/trunk/"
+    },
+    "main" : "./lib/proton.js",
+    "dependencies": {}
+}
diff --git a/proton-c/bindings/javascript/subscription.js b/proton-c/bindings/javascript/subscription.js
new file mode 100644
index 0000000..89fd1a3
--- /dev/null
+++ b/proton-c/bindings/javascript/subscription.js
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ *
+ */
+
+/*****************************************************************************/
+/*                                                                           */
+/*                               Subscription                                */
+/*                                                                           */
+/*****************************************************************************/
+
+/**
+ * Constructs a Subscription instance.
+ * @classdesc This class is a wrapper for Messenger's subscriptions.
+ * Subscriptions should never be *directly* instantiated by client code only via
+ * Messenger.subscribe() or Messenger.incomingSubscription(), so we declare the
+ * constructor in the scope of the package and don't export it via Module.
+ * @constructor Subscription
+ * @param {number} subscription a pointer to the underlying subscription object.
+ * @param {string} source the address that we want to subscribe to.
+ * @param {number} fd the file descriptor associated with the subscription. This
+ *                 is used internally to tidy up during error handling.
+ */
+var Subscription = function(subscription, source, fd) { // Subscription Constructor.
+    this._subscription = subscription;
+    this.source = source;
+    this.fd = fd;
+    if (source.indexOf('~') !== -1) {
+        this.passive = true;
+    } else {
+        this.passive = false;
+    }
+};
+
+/**
+ * TODO Not sure exactly what pn_subscription_get_context does.
+ * @method getContext
+ * @memberof! Subscription#
+ * @returns the Subscription's Context.
+ */
+Subscription.prototype['getContext'] = function() {
+    return _pn_subscription_get_context(this._subscription);
+};
+
+/**
+ * TODO Not sure exactly what pn_subscription_set_context does.
+ * @method setContext
+ * @memberof! Subscription#
+ * @param context the Subscription's new Context.
+ */
+Subscription.prototype['setContext'] = function(context) {
+    _pn_subscription_set_context(this._subscription, context);
+};
+
+/**
+ * @method getAddress
+ * @memberof! Subscription#
+ * @returns the Subscription's Address.
+ */
+Subscription.prototype['getAddress'] = function() {
+    if (this.passive) {
+        return this.source;
+    }
+    return Pointer_stringify(_pn_subscription_address(this._subscription));
+};
+
diff --git a/tests/javascript/codec.js b/tests/javascript/codec.js
new file mode 100644
index 0000000..ce4890d
--- /dev/null
+++ b/tests/javascript/codec.js
@@ -0,0 +1,569 @@
+#!/usr/bin/env node
+/*
+ * 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.
+ *
+ */
+
+/**
+ * This is a fairly literal JavaScript port of codec.py used to unit test the
+ * proton.Data wrapper class. This suite of tests is actually testing the low
+ * level implementation methods used to access the AMQP type system and in
+ * practice most normal users wouldn't need to call these directly, rather users
+ * should simply use the putObject() and getObject() methods.
+ */
+
+// Check if the environment is Node.js and if not log an error and exit.
+if (typeof process === 'object' && typeof require === 'function') {
+    var unittest = require("./unittest.js");
+    var assert = require("assert");
+
+    // Increase the virtual heap available to the emscripten compiled C runtime.
+    // This allows us to test a really big string.
+    PROTON_TOTAL_MEMORY = 140000000;
+    PROTON_TOTAL_STACK = 25000000; // Needs to be bigger than the biggest string.
+    var proton = require("qpid-proton");
+
+    // Extend TestCase by creating a prototype instance and adding test methods as properties.
+    var DataTest = new unittest.TestCase();
+
+    DataTest.setUp = function() {
+        this.data = new proton.Data();
+    };
+
+    DataTest.tearDown = function() {
+        this.data.free();
+        this.data = null;
+    };
+    
+    DataTest.testTopLevelNext = function() {
+        console.log("testTopLevelNext");
+        assert(this.data.next() === null);
+        this.data.putNULL();
+        this.data.putBOOL(false);
+        this.data.putINT(0);
+        assert(this.data.next() === null);
+        this.data.rewind();
+        assert(this.data.next() === proton.Data.NULL);
+        assert(this.data.next() === proton.Data.BOOL);
+        assert(this.data.next() === proton.Data.INT);
+        assert(this.data.next() === null);
+        console.log("OK\n");
+    };
+    
+    DataTest.testNestedNext = function() {
+        console.log("testNestedNext");
+        assert(this.data.next() === null);
+        this.data.putNULL();
+        assert(this.data.next() === null);
+        this.data.putLISTNODE();
+        assert(this.data.next() === null);
+        this.data.putBOOL(false);
+        assert(this.data.next() === null);
+        this.data.rewind();
+        assert(this.data.next() === proton.Data.NULL);
+        assert(this.data.next() === proton.Data.LIST);
+        this.data.enter();
+        assert(this.data.next() === null);
+        this.data.putUBYTE(0);
+        assert(this.data.next() === null);
+        this.data.putUINT(0);
+        assert(this.data.next() === null);
+        this.data.putINT(0);
+        assert(this.data.next() === null);
+        this.data.exit();
+        assert(this.data.next() === proton.Data.BOOL);
+        assert(this.data.next() === null);
+    
+        this.data.rewind();
+        assert(this.data.next() === proton.Data.NULL);
+        assert(this.data.next() === proton.Data.LIST);
+        assert(this.data.enter());
+        assert(this.data.next() === proton.Data.UBYTE);
+        assert(this.data.next() === proton.Data.UINT);
+        assert(this.data.next() === proton.Data.INT);
+        assert(this.data.next() === null);
+        assert(this.data.exit());
+        assert(this.data.next() === proton.Data.BOOL);
+        assert(this.data.next() === null);
+        console.log("OK\n");
+    };
+    
+    DataTest.testEnterExit = function() {
+        console.log("testEnterExit");
+        assert(this.data.next() === null);
+        assert(!this.data.enter());
+        this.data.putLISTNODE();
+        assert(this.data.enter());
+        assert(this.data.next() === null);
+        this.data.putLISTNODE();
+        assert(this.data.enter());
+        this.data.putLISTNODE();
+        assert(this.data.enter());
+        assert(this.data.exit());
+        assert(this.data.getLISTNODE() === 0);
+        assert(this.data.exit());
+        assert(this.data.getLISTNODE() === 1);
+        assert(this.data.exit());
+        assert(this.data.getLISTNODE() === 1);
+        assert(!this.data.exit());
+        assert(this.data.getLISTNODE() === 1);
+        assert(this.data.next() === null);
+    
+        this.data.rewind();
+        assert(this.data.next() === proton.Data.LIST);
+        assert(this.data.getLISTNODE() === 1);
+        assert(this.data.enter());
+        assert(this.data.next() === proton.Data.LIST);
+        assert(this.data.getLISTNODE() === 1);
+        assert(this.data.enter());
+        assert(this.data.next() === proton.Data.LIST);
+        assert(this.data.getLISTNODE() === 0);
+        assert(this.data.enter());
+        assert(this.data.next() === null);
+        assert(this.data.exit());
+        assert(this.data.getLISTNODE() === 0);
+        assert(this.data.exit());
+        assert(this.data.getLISTNODE() === 1);
+        assert(this.data.exit());
+        assert(this.data.getLISTNODE() === 1);
+        assert(!this.data.exit());
+        console.log("OK\n");
+    };
+    
+    /**
+     * This tests the "low level" putARRAYNODE/getARRAYNODE methods.
+     * In general though applications would create a proton.Data.Array and use the
+     * higher level putARRAY/getARRAY
+     */
+    DataTest._testArray = function(dtype, descriptor, atype, values) {
+        var values = Array.prototype.slice.apply(arguments, [3]);
+        dtype = (dtype == null) ? null : dtype.toUpperCase();
+        atype = atype.toUpperCase();
+    
+        // Create an array node, enter it and put the descriptor (if present) and values.
+        this.data.putARRAYNODE(dtype != null, proton.Data[atype]);
+        this.data.enter();
+        if (dtype != null) {
+            var putter = 'put' + dtype;
+            this.data[putter](descriptor);
+        }
+        var putter = 'put' + atype;
+        for (var i = 0; i < values.length; i++) {
+            this.data[putter](values[i]);
+        }
+        this.data.exit();
+    
+        // Check that we did indeed add an Array node
+        this.data.rewind();
+        assert(this.data.next() === proton.Data.ARRAY);
+    
+        // Get the count, described and type metadata from the array node and compare
+        // with the values we passed to putARRAYNODE.
+        var metadata = this.data.getARRAYNODE();
+        var count = metadata.count;
+        var described = metadata.described;
+        var type = metadata.type;
+    
+        assert(count === values.length);
+        if (dtype == null) {
+            assert(described === false);
+        } else {
+            assert(described === true);
+        }
+        assert(type === proton.Data[atype]);
+    
+        // Enter the array node and compare the descriptor and values with those that
+        // we put into the array.
+        assert(this.data.enter());
+        if (described) {
+            assert(this.data.next() === proton.Data[dtype]);
+            var getter = 'get' + dtype;
+            var gotten = this.data[getter]();
+            assert(gotten.toString() === descriptor.toString());
+        }
+        var getter = 'get' + atype;
+        for (var i = 0; i < values.length; i++) {
+            assert(this.data.next() === proton.Data[atype]);
+            var gotten = this.data[getter]();
+            assert(gotten.toString() === values[i].toString());
+        }
+        assert(this.data.next() === null);
+        assert(this.data.exit());
+    };
+    
+    DataTest.testStringArray = function() {
+        console.log("testStringArray");
+        this._testArray(null, null, "string", "one", "two", "three");
+    
+        // Now try using the proton.Data.Array class.
+        this.data.clear();
+        var put = new proton.Data.Array("STRING", ["four", "five", "six"]);
+        this.data.putARRAY(put);
+        var get = this.data.getARRAY();
+        assert(get.equals(put));
+        console.log("OK\n");
+    };
+    
+    DataTest.testDescribedStringArray = function() {
+        console.log("testDescribedStringArray");
+        this._testArray("symbol", "url", "string", "one", "two", "three");
+    
+        // Now try using the proton.Data.Array class.
+        this.data.clear();
+        var put = new proton.Data.Array("STRING", ["four", "five", "six"], new proton.Data.Symbol("url"));
+        this.data.putARRAY(put);
+        var get = this.data.getARRAY();
+        assert(get.equals(put));
+        console.log("OK\n");
+    };
+    
+    DataTest.testIntArray = function() {
+        console.log("testIntArray");
+        this._testArray(null, null, "int", 1, 2, 3);
+    
+        // Now try using the proton.Data.Array class.
+        this.data.clear();
+        var put = new proton.Data.Array("INT", [4, 5, 6]);
+        this.data.putARRAY(put);
+        var get = this.data.getARRAY();
+        assert(get.equals(put));
+        console.log("OK\n");
+    };
+    
+    DataTest.testUUIDArray = function() {
+        console.log("testUUIDArray");
+        this._testArray(null, null, "uuid", new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid());
+    
+        // Now try using the proton.Data.Array class.
+        this.data.clear();
+        var put = new proton.Data.Array("UUID", [new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid()]);
+        this.data.putARRAY(put);
+        var get = this.data.getARRAY();
+        assert(get.equals(put));
+        console.log("OK\n");
+    };
+
+    DataTest.testEmptyArray = function() {
+        console.log("testEmptyArray");
+        this._testArray(null, null, "null");
+
+        // Now try using the proton.Data.Array class.
+        this.data.clear();
+        var put = new proton.Data.Array();
+        this.data.putARRAY(put);
+        var get = this.data.getARRAY();
+        assert(get.equals(put));
+        console.log("OK\n");
+    };
+
+    DataTest.testDescribedEmptyArray = function() {
+        console.log("testDescribedEmptyArray");
+        this._testArray("long", 0, "null");
+    
+        // Now try using the proton.Data.Array class.
+        this.data.clear();
+        var put = new proton.Data.Array((0).long());
+        this.data.putARRAY(put);
+        var get = this.data.getARRAY();
+        assert(get.equals(put));
+        console.log("OK\n");
+    };  
+
+    DataTest._test = function(dtype, values) {
+        var values = Array.prototype.slice.apply(arguments, [1]);
+        var lastValue = values[values.length - 1];
+
+        // Default equality function. Note that we use valueOf because some of the
+        // types we are trying to compare (Symbol, Timestamp, Uuid etc.) are object
+        // types and we want to compare their value not whether they are the same object.
+        var eq = function(x, y) {return x.valueOf() === y.valueOf();};
+    
+        if (typeof lastValue === 'function') {
+            eq = values.pop();
+        }
+    
+        dtype = dtype.toUpperCase();
+        var ntype = proton.Data[dtype];
+        var putter = 'put' + dtype;
+        var getter = 'get' + dtype;
+    
+        for (var i = 0; i < values.length; i++) {
+            var v = values[i];
+            /*
+             * Replace the array element with its value. We do this to make testing
+             * simpler for Binary elements. In the case of Binary putBINARY "consumes"
+             * the data, in other words ownership of the underlying raw data transfers
+             * to the Data object so the v object becomes "empty" after calling the
+             * putter. Calling its valueOf() happens to call its toString() which
+             * provides a stringified version of the Binary whilst also working for
+             * the other data types we want to test too.
+             */
+            values[i] = v.valueOf();
+            this.data[putter](v);
+            var gotten = this.data[getter]();
+            assert(eq(gotten, values[i]));
+        }
+    
+        this.data.rewind();
+    
+        for (var i = 0; i < values.length; i++) {
+            var v = values[i];
+            var vtype = this.data.next();
+            assert(vtype === ntype);
+            var gotten = this.data[getter]();
+            assert(eq(gotten, v));
+        }
+    
+        // Test encode and decode methods.
+        var encoded = this.data.encode();
+        var copy = new proton.Data();
+        while (encoded) {
+            encoded = copy.decode(encoded);
+        }
+        copy.rewind();
+    
+        for (var i = 0; i < values.length; i++) {
+            var v = values[i];
+            var vtype = copy.next();
+            assert(vtype === ntype);
+            var gotten = copy[getter]();
+            assert(eq(gotten, v));
+        }
+        copy.free();
+    };  
+    
+    DataTest.testInt = function() {
+        console.log("testInt");
+        this._test("int", 1, 2, 3, -1, -2, -3);
+        console.log("OK\n");
+    
+    };  
+
+    DataTest.testString = function() {
+        console.log("testString");
+        this._test("string", "one", "two", "three", "this is a test", "");
+        console.log("OK\n");
+    };  
+
+    DataTest.testBigString = function() {
+        // Try a 2MB string, this is about as big as we can cope with using the default
+        // emscripten heap size.
+        console.log("testBigString");
+        var data = "";
+        for (var i = 0; i < 2000000; i++) {
+            data += "*";
+        }
+        var string = "start\n" + data + "\nfinish\n";
+        this._test("string", string);
+        console.log("OK\n");
+    };  
+
+/* TODO - currently emscripten isn't respecting Module['TOTAL_STACK'] so setting PROTON_TOTAL_STACK doesn't actually increase the stack size.
+    DataTest.testReallyBigString = function() {
+        // Try a 20MB string, this needs a bigger emscripten heap size and more stack
+        // as the default stack is 5MB and strings are allocated on the stack.
+        console.log("testReallyBigString");
+        var data = "";
+        for (var i = 0; i < 20000000; i++) {
+            data += "*";
+        }
+        var string = "start\n" + data + "\nfinish\n";
+        this._test("string", string);
+        console.log("OK\n");
+    };
+*/
+
+    DataTest.testFloat = function() {
+        console.log("testFloat");
+        // We have to use a special comparison here because JavaScript internally
+        // only uses doubles and converting between floats and doubles is imprecise.
+        this._test("float", 0, 1, 2, 3, 0.1, 0.2, 0.3, -1, -2, -3, -0.1, -0.2, -0.3,
+                   function(x, y) {return (x - y < 0.000001);});
+        console.log("OK\n");
+    };  
+
+    DataTest.testDouble = function() {
+        console.log("testDouble");
+        this._test("double", 0, 1, 2, 3, 0.1, 0.2, 0.3, -1, -2, -3, -0.1, -0.2, -0.3);
+        console.log("OK\n");
+    };  
+
+    DataTest.testBinary = function() {
+        console.log("testBinary");
+        this._test("binary", new proton.Data.Binary(["t".char(), "h".char(), "i".char(), "s".char()]),
+                   new proton.Data.Binary("is"), new proton.Data.Binary("a"), new proton.Data.Binary("test"),
+                   new proton.Data.Binary("of"), new proton.Data.Binary("двоичные данные"));
+        console.log("OK\n");
+    };  
+
+    DataTest.testSymbol = function() {
+        console.log("testSymbol");
+        this._test("symbol", new proton.Data.Symbol("this is a symbol test"),
+                             new proton.Data.Symbol("bleh"), new proton.Data.Symbol("blah"));
+        console.log("OK\n");
+    };
+
+    DataTest.testTimestamp = function() {
+        console.log("testTimestamp");
+        this._test("timestamp", new Date(0), new Date(12345), new Date(1000000));
+        console.log("OK\n");
+    };  
+
+    DataTest.testChar = function() {
+        console.log("testChar");
+        this._test("char", 'a', 'b', 'c', '\u1234');
+        console.log("OK\n");
+    };  
+
+    DataTest.testUUID = function() {
+        console.log("testUUID");
+        this._test("uuid", new proton.Data.Uuid(), new proton.Data.Uuid(), new proton.Data.Uuid());
+        console.log("OK\n");
+    };
+
+    /* TODO
+    DataTest.testDecimal32 = function() {
+        console.log("testDecimal32");
+        //this._test("decimal32", 0, 1, 2, 3, 4, Math.pow(2, 30));
+    };
+
+    DataTest.testDecimal64 = function() {
+        console.log("testDecimal64");
+        //this._test("decimal64", 0, 1, 2, 3, 4, Math.pow(2, 60));
+    };  
+
+    DataTest.testDecimal128 = function() {
+        console.log("testDecimal128");
+        // TODO
+    };
+    */
+
+    DataTest.testCopy = function() {
+        console.log("testCopy");
+        this.data.putDESCRIBEDNODE();
+        this.data.enter();
+        this.data.putULONG(123);
+        this.data.putMAPNODE();
+        this.data.enter();
+        this.data.putSTRING("pi");
+        this.data.putDOUBLE(3.14159265359);
+        this.data.exit();
+        this.data.exit();
+    
+        var dst = this.data.copy();
+        var copy = dst.format();
+        var orig = this.data.format();
+        assert(copy === orig);
+        dst.free();
+        console.log("OK\n");
+    };  
+
+    DataTest.testCopyNested = function() {
+        console.log("testCopyNested");
+        var nested = [1, 2, 3, [4, 5, 6], 7, 8, 9];
+        this.data.putObject(nested);
+        var dst = this.data.copy();
+        assert(dst.format() === this.data.format());
+        dst.free();
+        console.log("OK\n");
+    };  
+
+    DataTest.testCopyNestedArray = function() {
+        console.log("testCopyNestedArray");
+        var nested = [new proton.Data.Array("LIST", [
+                        ["first",  [new proton.Data.Array("INT", [1, 2, 3]), "this"]],
+                        ["second", [new proton.Data.Array("INT", [1, 2, 3]), "is"]],
+                        ["third",  [new proton.Data.Array("INT", [1, 2, 3]), "fun"]]
+                        ]),
+                    "end"];
+        this.data.putObject(nested);
+        var dst = this.data.copy();
+        assert(dst.format() === this.data.format());
+        dst.free();
+        console.log("OK\n");
+    };
+
+    DataTest.testRoundTrip = function() {
+        console.log("testRoundTrip");
+        var obj = {key: new Date(1234),
+                   123: "blah",
+                   c: "bleh",
+                   desc: new proton.Data.Described("http://example.org", new proton.Data.Symbol("url")),
+                   array: new proton.Data.Array("INT", [1, 2, 3]),
+                   list: [1, 2, 3, null, 4],
+                   boolean: true};
+        // Serialise obj into this.data.
+        this.data.putObject(obj);
+    
+        // Encode this.data into a Binary representation.
+        var enc = this.data.encode();
+    
+        // Create a new Data instance and decode from the Binary representation
+        // consuming the Binary contents in the process.
+        var data = new proton.Data();
+        data.decode(enc);
+    
+        assert(data.format() === this.data.format());
+    
+        // Deserialise from the copied Data instance into a new JavaScript Object.
+        data.rewind();
+        assert(data.next());
+        var copy = data.getObject();
+    
+        // Create yet another Data instance and serialise the new Object into that.
+        var data1 = new proton.Data();
+        data1.putObject(copy);
+    
+        // Compare the round tripped Data with the original one.
+        assert(data1.format() === this.data.format());
+    
+        data.free();
+        data1.free();
+        console.log("OK\n");
+    };
+
+    DataTest.testLookup = function() {
+        console.log("testLookup");
+        var obj = {key: "value",
+                   pi: 3.14159,
+                   list: [1, 2, 3, 4]};
+        // Serialise obj into this.data.
+        this.data.putObject(obj);
+        this.data.rewind();
+        this.data.next();
+        this.data.enter();
+        this.data.narrow();
+        assert(this.data.lookup("pi"));
+        assert(this.data.getObject() === 3.14159);
+        this.data.rewind();
+        assert(this.data.lookup("key"));
+        assert(this.data.getObject() === "value");
+        this.data.rewind();
+        assert(this.data.lookup("list"));
+        assert(this.data.getObject().toString() === "1,2,3,4");
+        this.data.widen();
+        this.data.rewind();
+        assert(!this.data.lookup("pi"));
+        console.log("OK\n");
+    };  
+
+    DataTest.run();
+} else {
+    console.error("codec.js should be run in Node.js");
+}
+
diff --git a/tests/javascript/message.js b/tests/javascript/message.js
new file mode 100644
index 0000000..dca6f68
--- /dev/null
+++ b/tests/javascript/message.js
@@ -0,0 +1,359 @@
+#!/usr/bin/env node
+/*
+ * 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.
+ *
+ */
+
+/**
+ * This is a fairly literal JavaScript port of message.py used to unit test the
+ * proton.Message wrapper class.
+ */
+
+// Check if the environment is Node.js and if not log an error and exit.
+if (typeof process === 'object' && typeof require === 'function') {
+    var unittest = require("./unittest.js");
+    var assert = require("assert");
+    var proton = require("qpid-proton");
+
+    /**
+     * JavaScript Implementation of Python's range() function taken from:
+     * http://stackoverflow.com/questions/8273047/javascript-function-similar-to-python-range
+     */
+    var range = function(start, stop, step) {
+        if (typeof stop == 'undefined') {
+            // one param defined
+            stop = start;
+            start = 0;
+        };
+        if (typeof step == 'undefined') {
+            step = 1;
+        };
+        if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
+            return [];
+        };
+        var result = [];
+        for (var i = start; step > 0 ? i < stop : i > stop; i += step) {
+            result.push(i);
+        };
+        return result;
+    };
+
+
+    // Extend TestCase by creating a new Test class as we're using it in a few places.
+    var Test = function() { // Test constructor.
+        /**
+         * The following call is the equivalent of "super" in Java. It's not necessary
+         * here as the unittest.TestCase constructor doesn't set any state, but it
+         * is the correct thing to do when implementing classical inheritance in
+         * JavaScript so I've kept it here as a useful reminder of the "pattern".
+         */
+        //unittest.TestCase.prototype.constructor.call(this);
+    };  
+
+    Test.prototype = new unittest.TestCase(); // Here's where the inheritance occurs.
+    Test.prototype.constructor = Test; // Otherwise instances of Test would have a constructor of unittest.TestCase.
+
+    Test.prototype.setUp = function() {
+        this.msg = new proton.Message();
+    };
+
+    Test.prototype.tearDown = function() {
+        this.msg.free();
+        this.msg = null;
+    };
+
+
+    // Extend Test more simply by creating a prototype instance and adding test methods as properties.
+
+    var AccessorsTest = new Test();
+
+    AccessorsTest._test = function(name, defaultValue, values) {
+        /**
+         * For the case of Binary values under test we retrieve their toString().
+         * This is because the methods under test "consume" the data, in other
+         * words ownership of the underlying raw data transfers to the Message
+         * object so the sent Binary object becomes "empty" after calling the setter.
+         * In addition Binary values merely contain a "pointer" to the raw data
+         * so even a "deepEqual" comparison won't accurately compare two Binaries.
+         * For these tests we "cheat" and store an array of characters in the
+         * Binary so that we can use their String forms for comparison tests.
+         *
+         * We also get the String value of Uuid for the case of setUserID because
+         * that method transparently creates Binary values from the String form
+         * of non-Binary data passed to it. It's a convenience method, but makes
+         * testing somewhat more fiddly.
+         */
+
+        // First get the values passed to the method.
+        var values = Array.prototype.slice.apply(arguments, [2]);
+        // If the first element of values is actually an Array then use the Array.
+        // This scenario is what happens in the tests that use the range() function.
+        values = (Object.prototype.toString.call(values[0]) === '[object Array]') ? values[0] : values;
+    
+        // Work out the accessor/mutator names noting that boolean accessors use "is" not "get".
+        var setter = 'set' + name;
+        var getter = (typeof defaultValue === 'boolean') ? 'is' + name : 'get' + name;
+    
+        // Get the message's default value first.
+        var d = this.msg[getter]();
+        d = (d instanceof proton.Data.Binary) ? d.toString() : d;
+    
+        // Compare the message's default with the expected default value passed in the test case.
+        assert.deepEqual(d, defaultValue);
+    
+        for (var i = 0; i < values.length; i++) {
+            var v = values[i];
+    
+            var value = (v instanceof proton.Data.Binary ||
+                         (name === 'UserID' && v instanceof proton.Data.Uuid)) ? v.toString() : v;
+            value = (v instanceof Date) ? v.valueOf() : v;
+    
+            this.msg[setter](v); // This call will "consume" Binary data.
+    
+            var gotten = this.msg[getter]();
+            gotten = (gotten instanceof proton.Data.Binary) ? gotten.toString() : gotten;
+            gotten = (gotten instanceof Date) ? gotten.valueOf() : v;
+    
+            assert.deepEqual(value, gotten);
+        }
+    };
+
+    AccessorsTest._testString = function(name) {
+        this._test(name, "", "asdf", "fdsa", "");
+    };  
+
+    AccessorsTest._testTime = function(name) {
+        // The ExpiryTime and CreationTime methods can take either a number or a Date Object.
+        this._test(name, new Date(0), new Date(0), 123456789, new Date(987654321));
+    };
+
+    AccessorsTest.testID = function() {
+        console.log("testID");
+        this._test("ID", null, "bytes", null, 123, "string", new proton.Data.Uuid(), new proton.Data.Binary("ВИНАРЫ"));
+        console.log("OK\n");
+    };  
+
+    AccessorsTest.testCorrelationID = function() {
+        console.log("testCorrelationID");
+        this._test("CorrelationID", null, "bytes", null, 123, "string", new proton.Data.Uuid(), new proton.Data.Binary("ВИНАРЫ"));
+        console.log("OK\n");
+    };
+
+    AccessorsTest.testDurable = function() {
+        console.log("testDurable");
+        this._test("Durable", false, true, false);
+        console.log("OK\n");
+    };
+
+    AccessorsTest.testPriority = function() {
+        console.log("testPriority");
+        this._test("Priority", proton.Message.DEFAULT_PRIORITY, range(0, 256));
+        console.log("OK\n");
+    };
+
+    AccessorsTest.testTTL = function() {
+        console.log("testTTL");
+        this._test("TTL", 0, range(12345, 54321));
+        console.log("OK\n");
+    };
+
+    AccessorsTest.testFirstAcquirer = function() {
+        console.log("testFirstAcquirer");
+        this._test("FirstAcquirer", false, true, false);
+        console.log("OK\n");
+    };
+
+    AccessorsTest.testDeliveryCount = function() {
+        console.log("testDeliveryCount");
+        this._test("DeliveryCount", 0, range(0, 1024));
+        console.log("OK\n");
+    };
+
+    AccessorsTest.testUserID = function() {
+        console.log("testUserID");
+        this._test("UserID", "", "asdf", "fdsa", 123, new proton.Data.Binary("ВИНАРЫ"), new proton.Data.Uuid(), "");
+        console.log("OK\n");
+    };
+
+    AccessorsTest.testAddress = function() {
+        console.log("testAddress");
+        this._testString("Address");
+        console.log("OK\n");
+    };
+
+    AccessorsTest.testSubject = function() {
+        console.log("testSubject");
+        this._testString("Subject");
+        console.log("OK\n");
+    };
+
+    AccessorsTest.testReplyTo = function() {
+        console.log("testReplyTo");
+        this._testString("ReplyTo");
+        console.log("OK\n");
+    };
+
+    AccessorsTest.testContentType = function() {
+        console.log("testContentType");
+        this._testString("ContentType");
+        console.log("OK\n");
+    };
+
+    AccessorsTest.testContentEncoding = function() {
+        console.log("testContentEncoding");
+        this._testString("ContentEncoding");
+        console.log("OK\n");
+    };
+
+    AccessorsTest.testExpiryTime = function() {
+        console.log("testExpiryTime");
+        this._testTime("ExpiryTime");
+        console.log("OK\n");
+    };
+
+    AccessorsTest.testCreationTime = function() {
+        console.log("testCreationTime");
+        this._testTime("CreationTime");
+        console.log("OK\n");
+    };
+
+    AccessorsTest.testGroupID = function() {
+        console.log("testGroupID");
+        this._testString("GroupID");
+        console.log("OK\n");
+    };
+
+    AccessorsTest.testGroupSequence = function() {
+        console.log("testGroupSequence");
+        this._test("GroupSequence", 0, 0, -10, 10, 20, -20);
+        console.log("OK\n");
+    };
+
+    AccessorsTest.testReplyToGroupID = function() {
+        console.log("testReplyToGroupID");
+        this._testString("ReplyToGroupID");
+        console.log("OK\n");
+    };
+
+
+    var CodecTest = new Test();
+
+    CodecTest.testRoundTrip = function() {
+        console.log("testRoundTrip");
+        this.msg.setID("asdf");
+        this.msg.setCorrelationID(new proton.Data.Uuid());
+        this.msg.setTTL(3);
+        this.msg.setPriority(100);
+        this.msg.setAddress("address");
+        this.msg.setSubject("subject");
+        this.msg.body = "Hello World!";
+    
+        var data = this.msg.encode();
+        var msg2 = new proton.Message();
+        msg2.decode(data);
+    
+        assert(this.msg.getID() === msg2.getID());
+        assert(this.msg.getCorrelationID().toString() === msg2.getCorrelationID().toString());
+        assert(this.msg.getTTL() === msg2.getTTL());
+        assert(this.msg.getPriority() === msg2.getPriority());
+        assert(this.msg.getAddress() === msg2.getAddress());
+        assert(this.msg.getSubject() === msg2.getSubject());
+        assert(this.msg.body === msg2.body);
+
+        msg2.free();
+        console.log("OK\n");
+    };
+
+    /**
+     * This test tests the transparent serialisation and deserialisation of JavaScript
+     * Objects using the AMQP type system (this is the default behaviour).
+     */
+    CodecTest.testRoundTripBodyObject = function() {
+        console.log("testRoundTripBodyObject");
+        this.msg.setAddress("address");
+        this.msg.body = {array: [1, 2, 3, 4], object: {name: "John Smith", age: 65}};
+
+        var data = this.msg.encode();
+        var msg2 = new proton.Message();
+        msg2.decode(data);
+    
+        assert(this.msg.getAddress() === msg2.getAddress());
+        assert(this.msg.getContentType() === msg2.getContentType());
+        assert.deepEqual(this.msg.body, msg2.body);
+
+        msg2.free();
+        console.log("OK\n");
+    };
+
+    /**
+     * This test tests the transparent serialisation and deserialisation of JavaScript
+     * Objects as JSON. In this case the "on-the-wire" representation is an AMQP binary
+     * stored in the AMQP data section.
+     */
+    CodecTest.testRoundTripBodyObjectAsJSON = function() {
+        console.log("testRoundTripBodyObjectAsJSON");
+        this.msg.setAddress("address");
+        this.msg.setContentType("application/json");
+        this.msg.body = {array: [1, 2, 3, 4], object: {name: "John Smith", age: 65}};
+    
+        var data = this.msg.encode();
+        var msg2 = new proton.Message();
+        msg2.decode(data);
+    
+        assert(this.msg.getAddress() === msg2.getAddress());
+        assert(this.msg.getContentType() === msg2.getContentType());
+        assert.deepEqual(this.msg.body, msg2.body);
+    
+        msg2.free();
+        console.log("OK\n");
+    };
+
+    /**
+     * By default the API will encode using the AMQP type system, but is the content-type
+     * is set it will encode as an opaque Binary in an AMQP data section. For certain
+     * types however this isn't the most useful thing. For application/json (see
+     * previous test) we convert to and from JavaScript Objects and for text/* MIME
+     * types the API will automatically convert the received Binary into a String.
+     */
+    CodecTest.testRoundTripMIMETextObject = function() {
+        console.log("testRoundTripMIMETextObject");
+        this.msg.setAddress("address");
+        this.msg.setContentType("text/plain");
+        this.msg.body = "some text";
+    
+        var data = this.msg.encode();
+        var msg2 = new proton.Message();
+        msg2.decode(data);
+
+        assert(this.msg.getAddress() === msg2.getAddress());
+        assert(this.msg.getContentType() === msg2.getContentType());
+        assert.deepEqual(this.msg.body, msg2.body);
+
+        msg2.free();
+        console.log("OK\n");
+    };
+
+
+    // load and save are deprecated so not implemented in the JavaScript binding.
+
+    AccessorsTest.run();
+    CodecTest.run();
+} else {
+    console.error("message.js should be run in Node.js");
+}
+
diff --git a/tests/javascript/soak.js b/tests/javascript/soak.js
new file mode 100755
index 0000000..8ecce6a
--- /dev/null
+++ b/tests/javascript/soak.js
@@ -0,0 +1,93 @@
+#!/usr/bin/env node
+/*
+ * 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.
+ *
+ */
+
+// Check if the environment is Node.js and if not log an error and exit.
+if (typeof process === 'object' && typeof require === 'function') {
+    var proton = require("qpid-proton");
+
+    var addr = 'guest:guest@localhost:5673';
+    //var addr = 'localhost:5673';
+    var address = 'amqp://' + addr;
+    console.log(address);
+
+    var subscriptionQueue = '';
+    var count = 0;
+    var start = 0; // Start Time.
+
+    var message = new proton.Message();
+    var messenger = new proton.Messenger();
+
+    var pumpData = function() {
+        while (messenger.incoming()) {
+            // The second parameter forces Binary payloads to be decoded as strings
+            // this is useful because the broker QMF Agent encodes strings as AMQP
+            // binary, which is a right pain from an interoperability perspective.
+            var t = messenger.get(message, true);
+            //console.log("Address: " + message.getAddress());
+            //console.log("Content: " + message.body);
+            messenger.accept(t);
+    
+            if (count % 1000 === 0) {
+                var time = +new Date();
+                console.log("count = " + count + ", duration = " + (time - start) + ", rate = " + ((count*1000)/(time - start)));
+            }
+
+            sendMessage();
+        }
+
+        if (messenger.isStopped()) {
+            message.free();
+            messenger.free();
+        }
+    };
+
+    var sendMessage = function() {
+        var msgtext = "Message Number " + count;
+        count++;
+
+        message.setAddress(address + '/' + subscriptionQueue);
+        message.body = msgtext;
+        messenger.put(message);
+        //messenger.settle();
+    };
+
+    messenger.on('error', function(error) {console.log(error);});
+    messenger.on('work', pumpData);
+    messenger.on('subscription', function(subscription) {
+        var subscriptionAddress = subscription.getAddress();
+        var splitAddress = subscriptionAddress.split('/');
+        subscriptionQueue = splitAddress[splitAddress.length - 1];
+
+        console.log("Subscription Queue: " + subscriptionQueue);
+        start = +new Date();
+        sendMessage();
+    });
+
+    //messenger.setOutgoingWindow(1024);
+    messenger.setIncomingWindow(1024); // The Java Broker seems to need this.
+    messenger.recv(); // Receive as many messages as messenger can buffer.
+    messenger.start();
+
+    messenger.subscribe('amqp://' + addr + '/#');
+} else {
+    console.error("soak.js should be run in Node.js");
+}
+
diff --git a/tests/javascript/unittest.js b/tests/javascript/unittest.js
new file mode 100644
index 0000000..bc1567c
--- /dev/null
+++ b/tests/javascript/unittest.js
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ *
+ */
+
+/**
+ * The TestCase class provides a simple dependency-free Unit Test framework to
+ * automagically invoke methods that start with "test" on classes that extend it.
+ */
+
+// TestCase Constructor
+var TestCase = function() {};
+
+// Enumerate all functions of the class and invoke those beginning with "test".
+TestCase.prototype.run = function() {
+    for (var property in this) {
+        if ((typeof this[property] === 'function') &&
+            property.lastIndexOf('test', 0) === 0) {
+            this.setUp();
+            this[property]();
+            this.tearDown();
+        }
+    }
+};
+
+TestCase.prototype.setUp = function() {};
+TestCase.prototype.tearDown = function() {};
+
+module.exports.TestCase = TestCase;
+
diff --git a/tools/cmake/Modules/FindEmscripten.cmake b/tools/cmake/Modules/FindEmscripten.cmake
new file mode 100644
index 0000000..7289731
--- /dev/null
+++ b/tools/cmake/Modules/FindEmscripten.cmake
@@ -0,0 +1,40 @@
+#
+# 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.
+#
+
+# FindEmscripten
+# This module checks if Emscripten and its prerequisites are installed and if so
+# sets EMSCRIPTEN_FOUND Emscripten (https://github.com/kripken/emscripten) is a
+# C/C++ to JavaScript cross-compiler used to generate the JavaScript bindings.
+
+if (NOT EMSCRIPTEN_FOUND)
+    # First check that Node.js is installed as that is needed by Emscripten.
+    find_program(NODE node)
+    if (NOT NODE)
+        message(STATUS "Node.js (http://nodejs.org) is not installed: can't build JavaScript binding")
+    else (NOT NODE)
+        # Check that the Emscripten C/C++ to JavaScript cross-compiler is installed.
+        find_program(EMCC emcc)
+        if (NOT EMCC)
+            message(STATUS "Emscripten (https://github.com/kripken/emscripten) is not installed: can't build JavaScript binding")
+        else (NOT EMCC)
+            set(EMSCRIPTEN_FOUND ON)
+        endif (NOT EMCC)
+    endif (NOT NODE)
+endif (NOT EMSCRIPTEN_FOUND)
+
diff --git a/tools/cmake/Modules/FindNodePackages.cmake b/tools/cmake/Modules/FindNodePackages.cmake
new file mode 100644
index 0000000..bfbb36f
--- /dev/null
+++ b/tools/cmake/Modules/FindNodePackages.cmake
@@ -0,0 +1,69 @@
+#
+# 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.
+#
+
+# FindNodePackages
+# This module finds and installs (using npm) node.js packages that are used by
+# the JavaScript binding. The binding should still compile if these packages
+# cannot be installed but certain features might not work as described below.
+#
+# * The ws package is the WebSocket library used by emscripten when the target is
+#   node.js, it isn't needed for applications hosted on a browser (where native 
+#   WebSockets will be used), but without it it won't work with node.js.
+#
+# * The jsdoc package is a JavaScript API document generator analogous to Doxygen
+#   or JavaDoc, it is used by the docs target in the JavaScript binding.
+
+if (NOT NODE_PACKAGES_FOUND)
+    # Check if the specified node.js package is already installed, if not install it.
+    macro(InstallPackage varname name)
+        execute_process(
+            COMMAND npm list --local ${name}
+            OUTPUT_VARIABLE check_package
+        )
+
+        set(${varname} OFF)
+
+        if (check_package MATCHES "${name}@.")
+            message(STATUS "Found node.js package: ${name}")
+            set(${varname} ON)
+        else()
+            message(STATUS "Installing node.js package: ${name}")
+
+            execute_process(
+                COMMAND npm install ${name}
+                WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+                OUTPUT_VARIABLE var
+            )
+
+            if (var)
+                message(STATUS "Installed node.js package: ${name}")
+                set(${varname} ON)
+            endif (var)
+        endif()
+    endmacro()
+
+    # Check if ws WebSocket library https://github.com/einaros/ws is installed
+    InstallPackage("NODE_WS_FOUND" "ws")
+
+    # Check if jsdoc3 API documentation generator https://github.com/jsdoc3/jsdoc is installed
+    InstallPackage("NODE_JSDOC_FOUND" "jsdoc")
+
+    set(NODE_PACKAGES_FOUND ON)
+endif (NOT NODE_PACKAGES_FOUND)
+