You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by he...@apache.org on 2013/09/20 19:45:30 UTC

git commit: THRIFT-2190 Add the JavaScript thrift.js lib to the Bower registry Client: nodejs Patch: Randy Abernethy

Updated Branches:
  refs/heads/master e594dccc8 -> 095ddb7ff


THRIFT-2190 Add the JavaScript thrift.js lib to the Bower registry
Client: nodejs
Patch: Randy Abernethy

plus path changes


Project: http://git-wip-us.apache.org/repos/asf/thrift/repo
Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/095ddb7f
Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/095ddb7f
Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/095ddb7f

Branch: refs/heads/master
Commit: 095ddb7ff8c9e503c2186e8452f2de7f7451212a
Parents: e594dcc
Author: Henrique Mendonça <he...@apache.org>
Authored: Fri Sep 20 19:38:03 2013 +0200
Committer: Henrique Mendonça <he...@apache.org>
Committed: Fri Sep 20 19:38:03 2013 +0200

----------------------------------------------------------------------
 lib/js/Gruntfile.js            |   70 +++
 lib/js/README                  |   68 ++-
 lib/js/package.json            |   12 +
 lib/js/src/thrift.js           | 1103 +++++++++++++++++++++++++++++++++++
 lib/js/test/build.xml          |    6 +-
 lib/js/test/phantomjs-qunit.js |   10 +-
 lib/js/test/test.html          |    2 +-
 lib/js/test/test.js            |    6 +-
 lib/js/thrift.js               |  779 -------------------------
 9 files changed, 1252 insertions(+), 804 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/thrift/blob/095ddb7f/lib/js/Gruntfile.js
----------------------------------------------------------------------
diff --git a/lib/js/Gruntfile.js b/lib/js/Gruntfile.js
new file mode 100644
index 0000000..dd6406b
--- /dev/null
+++ b/lib/js/Gruntfile.js
@@ -0,0 +1,70 @@
+//To build dist/thrift.js, dist/thrift.min.js and doc/*
+//run grunt at the command line in this directory.
+//Prerequisites:
+// Node Setup -   nodejs.org
+// Grunt Setup -  npm install  //reads the ./package.json and installs project dependencies
+
+module.exports = function(grunt) {
+  'use strict';
+
+  grunt.initConfig({
+    pkg: grunt.file.readJSON('package.json'),
+    concat: {
+      options: {
+        separator: ';'
+      },
+      dist: {
+        src: ['src/**/*.js'],
+        dest: 'dist/<%= pkg.name %>.js'
+      }
+    },
+    jsdoc : {
+        dist : {
+            src: ['src/*.js', './README'], 
+            options: {
+              destination: 'doc'
+            }
+        }
+    },
+    uglify: {
+      options: {
+        banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
+      },
+      dist: {
+        files: {
+          'dist/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>']
+        }
+      }
+    },
+    qunit: {
+      all: {
+        options: {
+          urls: [
+            'http://localhost:8088/test.html'
+          ]
+        }
+      }
+    },
+    jshint: {
+      files: ['Gruntfile.js', 'src/**/*.js', 'test/*.js'],
+      options: {
+        // options here to override JSHint defaults
+        globals: {
+          jQuery: true,
+          console: true,
+          module: true,
+          document: true
+        }
+      }
+    },
+  });
+
+  grunt.loadNpmTasks('grunt-contrib-uglify');
+  grunt.loadNpmTasks('grunt-contrib-jshint');
+  grunt.loadNpmTasks('grunt-contrib-qunit');
+  grunt.loadNpmTasks('grunt-contrib-concat');
+  grunt.loadNpmTasks('grunt-jsdoc');
+
+  grunt.registerTask('test', ['jshint', 'qunit']);
+  grunt.registerTask('default', ['jshint', 'qunit', 'concat', 'uglify', 'jsdoc']);
+};
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/thrift/blob/095ddb7f/lib/js/README
----------------------------------------------------------------------
diff --git a/lib/js/README b/lib/js/README
index fafdc43..98a1b54 100644
--- a/lib/js/README
+++ b/lib/js/README
@@ -1,8 +1,10 @@
 Thrift Javascript Library
+=========================
+This browser based Apache Thrift implementation supports
+RPC using the JSON protocol over Http[s] with XHR.
 
 License
-=======
-
+-------
 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
@@ -20,21 +22,53 @@ KIND, either express or implied. See the License for the
 specific language governing permissions and limitations
 under the License.
 
-Using Thrift with Javascript
-=====================
-
-Allows javascript client interfaces to Thrift services.
-This is geared for use in a web browser.
+Example
+-------
+The listing below demonstrates a simple browser based JavaScript
+Thrift client and Node.js JavaScript server for the HelloSvc service. 
 
-This client can only speak the JSON Protocol and the only supported
-transport is AJAX.
+### hello.thrift - Service IDL
+    service HelloSvc {
+        string hello_func(),
+    }
 
-There is a test httpd service in the test dir that requires
-http://hc.apache.org under test dir
+### hello.html - Browser Client
+    <!doctype html>
+    <html lang="en">
+    <head>
+        <script src="thrift.js" type="text/javascript"></script>
+        <script src="gen-js/HelloSvc.js" type="text/javascript"></script>
+    </head>
+    <body>
+        <h1>Apache Thrift JavaScript Browser Client Demo</h1>
+        <button id="btn">Get Message from Node Server</button>
+        <script type="text/javascript">
+            document.getElementById("btn").addEventListener("click", getMessage, false);
+    
+            function getMessage() {
+                var transport = new Thrift.Transport("http://localhost:8585");
+                var protocol  = new Thrift.Protocol(transport);
+                var client = new HelloSvcClient(protocol);
+                var msg = client.hello_func();
+                document.getElementById("output").innerHTML = msg;
+            }
+        </script>
+        <h2>Server Response: <div id="output"></div></h2>
+    </body> 
+    </html>
 
-Dependencies
-============
-A JavaScript enabled browser. Tested with:
- *IE 6,7,8
- *FF 2,3
- *Safari 3 & 4
+### hello.js - Node Server
+    var thrift = require('thrift');
+    var TJSONProtocol = require('thrift/protocol').TJSONProtocol;
+    var HelloSvc = require('./gen-nodejs/HelloSvc.js');
+    
+    var call_counter = 0;
+        
+    var server = thrift.createHttpGetPostServer(HelloSvc, {
+      hello_func: function(result) {
+        console.log("Client call: " + (++call_counter));
+        result(null, "Hello Apache Thrift for JavaScript " + call_counter);
+      }
+    }, {protocol: TJSONProtocol});
+    
+    server.listen(8585);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/thrift/blob/095ddb7f/lib/js/package.json
----------------------------------------------------------------------
diff --git a/lib/js/package.json b/lib/js/package.json
new file mode 100644
index 0000000..5a8485b
--- /dev/null
+++ b/lib/js/package.json
@@ -0,0 +1,12 @@
+{
+  "name": "thrift",
+  "version": "1.0.0",
+  "devDependencies": {
+    "grunt": "~0.4.1",
+    "grunt-contrib-uglify": "~0.2.2",
+    "grunt-contrib-jshint": "~0.6.3",
+    "grunt-contrib-qunit": "~0.2.2",
+    "grunt-contrib-concat": "~0.3.0",
+    "grunt-jsdoc": "~0.4.0"
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/thrift/blob/095ddb7f/lib/js/src/thrift.js
----------------------------------------------------------------------
diff --git a/lib/js/src/thrift.js b/lib/js/src/thrift.js
new file mode 100644
index 0000000..3b489e5
--- /dev/null
+++ b/lib/js/src/thrift.js
@@ -0,0 +1,1103 @@
+/*
+ * 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.
+ */
+
+/*jshint evil:true*/
+
+/**
+ * The Thrift namespace houses the Apache Thrift JavaScript library 
+ * elements providing JavaScript bindings for the Apache Thrift RPC 
+ * system. Users will typically only directly make use of the 
+ * Transport and Protocol constructors.
+ * @namespace
+ * @example
+ *     var transport = new Thrift.Transport("http://localhost:8585");
+ *     var protocol  = new Thrift.Protocol(transport);
+ *     var client = new MyThriftSvcClient(protocol);
+ *     var result = client.MyMethod();
+ */
+var Thrift = {
+    /**
+     * Thrift JavaScript library version.
+     * @readonly
+     * @const {string} Version
+     * @memberof Thrift
+     */
+    Version: '1.0.0-dev',
+
+    /**
+     * Thrift IDL type string to Id mapping.
+     * @readonly
+     * @property {number}  STOP   - End of a set of fields.
+     * @property {number}  VOID   - No value (only legal for return types).
+     * @property {number}  BOOL   - True/False integer.
+     * @property {number}  BYTE   - Signed 8 bit integer.
+     * @property {number}  I08    - Signed 8 bit integer.     
+     * @property {number}  DOUBLE - 64 bit IEEE 854 floating point.
+     * @property {number}  I16    - Signed 16 bit integer.
+     * @property {number}  I32    - Signed 32 bit integer.
+     * @property {number}  I64    - Signed 64 bit integer.
+     * @property {number}  STRING - Array of bytes representing a string of characters.
+     * @property {number}  UTF7   - Array of bytes representing a string of UTF7 encoded characters.
+     * @property {number}  STRUCT - A multifield type.
+     * @property {number}  MAP    - A collection type (map/associative-array/dictionary).
+     * @property {number}  SET    - A collection type (unordered and without repeated values).
+     * @property {number}  LIST   - A collection type (unordered).
+     * @property {number}  UTF8   - Array of bytes representing a string of UTF8 encoded characters.
+     * @property {number}  UTF16  - Array of bytes representing a string of UTF16 encoded characters.
+     */
+    Type: {
+        'STOP' : 0,
+        'VOID' : 1,
+        'BOOL' : 2,
+        'BYTE' : 3,
+        'I08' : 3,
+        'DOUBLE' : 4,
+        'I16' : 6,
+        'I32' : 8,
+        'I64' : 10,
+        'STRING' : 11,
+        'UTF7' : 11,
+        'STRUCT' : 12,
+        'MAP' : 13,
+        'SET' : 14,
+        'LIST' : 15,
+        'UTF8' : 16,
+        'UTF16' : 17
+    },
+
+    /**
+     * Thrift RPC message type string to Id mapping.
+     * @readonly
+     * @property {number}  CALL      - RPC call sent from client to server.
+     * @property {number}  REPLY     - RPC call normal response from server to client.
+     * @property {number}  EXCEPTION - RPC call exception response from server to client.
+     * @property {number}  ONEWAY    - Oneway RPC call from client to server with no response.
+     */
+    MessageType: {
+        'CALL' : 1,
+        'REPLY' : 2,
+        'EXCEPTION' : 3,
+        'ONEWAY' : 4
+    },
+
+    /**
+     * Utility function returning the count of an object's own properties.
+     * @param {object} obj - Object to test.
+     * @returns {number} number of object's own properties
+     */
+    objectLength: function(obj) {
+        var length = 0;
+        for (var k in obj) {
+            if (obj.hasOwnProperty(k)) {
+                length++;
+            }
+        }
+
+        return length;
+    },
+
+    /**
+     * Utility function to establish prototype inheritance.
+     * @see {@link http://javascript.crockford.com/prototypal.html|Prototypal Inheritance}
+     * @param {function} constructor - Contstructor function to set as derived.
+     * @param {function} superConstructor - Contstructor function to set as base.
+     * @param {string} [name] - Type name to set as name property in derived prototype.
+     */
+    inherits: function(constructor, superConstructor, name) {
+      function F() {}
+      F.prototype = superConstructor.prototype;
+      constructor.prototype = new F();
+      constructor.prototype.name = name || "";
+    }
+};
+
+/**
+ * Initializes a Thrift TException instance.
+ * @constructor
+ * @augments Error
+ * @param {string} message - The TException message (distinct from the Error message).
+ * @classdesc TException is the base class for all Thrift exceptions types.
+ */
+Thrift.TException = function(message) {
+    this.message = message;
+};
+Thrift.inherits(Thrift.TException, Error, 'TException');
+
+/**
+ * Returns the message set on the exception.
+ * @readonly
+ * @returns {string} exception message
+ */
+Thrift.TException.prototype.getMessage = function() {
+    return this.message;
+};
+
+/**
+ * Thrift Application Exception type string to Id mapping.
+ * @readonly
+ * @property {number}  UNKNOWN                 - Unknown/undefined.
+ * @property {number}  UNKNOWN_METHOD          - Client attempted to call a method unknown to the server.
+ * @property {number}  INVALID_MESSAGE_TYPE    - Client passed an unknown/unsupported MessageType.
+ * @property {number}  WRONG_METHOD_NAME       - Unused.
+ * @property {number}  BAD_SEQUENCE_ID         - Unused in Thrift RPC, used to flag proprietary sequence number errors.
+ * @property {number}  MISSING_RESULT          - Raised by a server processor if a handler fails to supply the required return result.
+ * @property {number}  INTERNAL_ERROR          - Something bad happened.
+ * @property {number}  PROTOCOL_ERROR          - The protocol layer failed to serialize or deserialize data.
+ * @property {number}  INVALID_TRANSFORM       - Unused.
+ * @property {number}  INVALID_PROTOCOL        - The protocol (or version) is not supported.
+ * @property {number}  UNSUPPORTED_CLIENT_TYPE - Unused.
+ */
+Thrift.TApplicationExceptionType = {
+    'UNKNOWN' : 0,
+    'UNKNOWN_METHOD' : 1,
+    'INVALID_MESSAGE_TYPE' : 2,
+    'WRONG_METHOD_NAME' : 3,
+    'BAD_SEQUENCE_ID' : 4,
+    'MISSING_RESULT' : 5,
+    'INTERNAL_ERROR' : 6,
+    'PROTOCOL_ERROR' : 7,
+    'INVALID_TRANSFORM' : 8,
+    'INVALID_PROTOCOL' : 9,
+    'UNSUPPORTED_CLIENT_TYPE' : 10
+};
+
+/**
+ * Initializes a Thrift TApplicationException instance.
+ * @constructor
+ * @augments Thrift.TException
+ * @param {string} message - The TApplicationException message (distinct from the Error message).
+ * @param {Thrift.TApplicationExceptionType} [code] - The TApplicationExceptionType code.
+ * @classdesc TApplicationException is the exception class used to propagate exceptions from an RPC server back to a calling client.
+*/
+Thrift.TApplicationException = function(message, code) {
+    this.message = message;
+    this.code = typeof code === "number" ? code : 0;
+};
+Thrift.inherits(Thrift.TApplicationException, Thrift.TException, 'TApplicationException');
+
+/**
+ * Read a TApplicationException from the supplied protocol.
+ * @param {object} input - The input protocol to read from.
+ */
+Thrift.TApplicationException.prototype.read = function(input) {
+    while (1) {
+        var ret = input.readFieldBegin();
+
+        if (ret.ftype == Thrift.Type.STOP) {
+            break;
+        }
+
+        var fid = ret.fid;
+
+        switch (fid) {
+            case 1:
+                if (ret.ftype == Thrift.Type.STRING) {
+                    ret = input.readString();
+                    this.message = ret.value;
+                } else {
+                    ret = input.skip(ret.ftype);
+                }
+                break;
+            case 2:
+                if (ret.ftype == Thrift.Type.I32) {
+                    ret = input.readI32();
+                    this.code = ret.value;
+                } else {
+                    ret = input.skip(ret.ftype);
+                }
+                break;
+           default:
+                ret = input.skip(ret.ftype);
+                break;
+        }
+
+        input.readFieldEnd();
+    }
+
+    input.readStructEnd();
+};
+
+/**
+ * Wite a TApplicationException to the supplied protocol.
+ * @param {object} output - The output protocol to write to.
+ */
+Thrift.TApplicationException.prototype.write = function(output) {
+    output.writeStructBegin('TApplicationException');
+
+    if (this.message) {
+        output.writeFieldBegin('message', Thrift.Type.STRING, 1);
+        output.writeString(this.getMessage());
+        output.writeFieldEnd();
+    }
+
+    if (this.code) {
+        output.writeFieldBegin('type', Thrift.Type.I32, 2);
+        output.writeI32(this.code);
+        output.writeFieldEnd();
+    }
+
+    output.writeFieldStop();
+    output.writeStructEnd();
+};
+
+/**
+ * Returns the application exception code set on the exception.
+ * @readonly
+ * @returns {Thrift.TApplicationExceptionType} exception code
+ */
+Thrift.TApplicationException.prototype.getCode = function() {
+    return this.code;
+};
+
+/**
+ * Initializes a Thrift Http[s] transport instance.
+ * Note: If you do not specify a url then you must handle XHR on your own
+ *       (this is how to use js bindings in a async fashion).
+ * @constructor
+ * @param {string} [url] - The URL to connect to.
+ * @classdesc The Apache Thrift Transport layer performs byte level I/O between RPC
+ * clients and servers. The JavaScript Transport object type uses Http[s]/XHR and is
+ * the sole browser based Thrift transport. Target servers must implement the http[s] 
+ * transport (see: node.js example server).
+ * @example
+ *     var transport = new Thrift.Transport("http://localhost:8585");
+ */
+Thrift.Transport = function(url) {
+    this.url = url;
+    this.wpos = 0;
+    this.rpos = 0;
+
+    this.send_buf = '';
+    this.recv_buf = '';
+};
+
+Thrift.Transport.prototype = {
+    /**
+     * Gets the browser specific XmlHttpRequest Object.
+     * @returns {object} the browser XHR interface object
+     */
+    getXmlHttpRequestObject: function() {
+        try { return new XMLHttpRequest(); } catch (e1) { }
+        try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch (e2) { }
+        try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch (e3) { }
+
+        throw "Your browser doesn't support XHR.";
+    },
+
+    /**
+     * Sends the current XRH request if the transport was created with a URL and
+     * the async parameter if false. If the transport was not created with a URL
+     * or the async parameter is True or the URL is an empty string, the current 
+     * send buffer is returned.
+     * @param {object} async - If true the current send buffer is returned.
+     * @returns {undefined|string} Nothing or the current send buffer.
+     * @throws {string} If XHR fails.
+     */
+    flush: function(async) {
+        //async mode
+        if (async || this.url === undefined || this.url === '') {
+            return this.send_buf;
+        }
+
+        var xreq = this.getXmlHttpRequestObject();
+
+        if (xreq.overrideMimeType) {
+            xreq.overrideMimeType('application/json');
+        }
+
+        xreq.open('POST', this.url, false);
+        xreq.send(this.send_buf);
+
+        if (xreq.readyState != 4) {
+            throw 'encountered an unknown ajax ready state: ' + xreq.readyState;
+        }
+
+        if (xreq.status != 200) {
+            throw 'encountered a unknown request status: ' + xreq.status;
+        }
+
+        this.recv_buf = xreq.responseText;
+        this.recv_buf_sz = this.recv_buf.length;
+        this.wpos = this.recv_buf.length;
+        this.rpos = 0;
+    },
+
+    /**
+     * Creates a jQuery XHR object to be used for a Thrift server call.
+     * @param {object} client - The Thrift Service client object generated by the IDL compiler.
+     * @param {object} postData - The message to send to the server.
+     * @param {function} args - The function to call if the request suceeds.
+     * @param {function} recv_method - The Thrift Service Client receive method for the call.
+     * @returns {object} A new jQuery XHR object.
+     * @throws {string} If the jQuery version is prior to 1.5 or if jQuery is not found.
+     */
+    jqRequest: function(client, postData, args, recv_method) {
+        if (typeof jQuery === 'undefined' ||
+            typeof jQuery.Deferred === 'undefined') {
+            throw 'Thrift.js requires jQuery 1.5+ to use asynchronous requests';
+        }
+
+        var thriftTransport = this;
+
+        var jqXHR = jQuery.ajax({
+            url: this.url,
+            data: postData,
+            type: 'POST',
+            cache: false,
+            contentType: 'application/json',
+            dataType: 'text thrift',
+            converters: {
+                'text thrift' : function(responseData) {
+                    thriftTransport.setRecvBuffer(responseData);
+                    var value = recv_method.call(client);
+                    return value;
+                }
+            },
+            context: client,
+            success: jQuery.makeArray(args).pop()
+        });
+
+        return jqXHR;
+    },
+
+    /**
+     * Sets the buffer to use when receiving server responses.
+     * @param {string} buf - The buffer to receive server responses.
+     */
+    setRecvBuffer: function(buf) {
+        this.recv_buf = buf;
+        this.recv_buf_sz = this.recv_buf.length;
+        this.wpos = this.recv_buf.length;
+        this.rpos = 0;
+    },
+
+    /**
+     * Returns true if the transport is open, in browser based JavaScript
+     * this function always returns true.
+     * @readonly
+     * @returns {boolean} Always True.
+     */    
+    isOpen: function() {
+        return true;
+    },
+
+    /**
+     * Opens the transport connection, in browser based JavaScript
+     * this function is a nop.
+     */    
+    open: function() {},
+
+    /**
+     * Closes the transport connection, in browser based JavaScript
+     * this function is a nop.
+     */    
+    close: function() {},
+
+    /**
+     * Returns the specified number of characters from the response
+     * buffer.
+     * @param {number} len - The number of characters to return.
+     * @returns {string} Characters sent by the server.
+     */
+    read: function(len) {
+        var avail = this.wpos - this.rpos;
+
+        if (avail === 0) {
+            return '';
+        }
+
+        var give = len;
+
+        if (avail < len) {
+            give = avail;
+        }
+
+        var ret = this.read_buf.substr(this.rpos, give);
+        this.rpos += give;
+
+        //clear buf when complete?
+        return ret;
+    },
+
+    /**
+     * Returns the entire response buffer.
+     * @returns {string} Characters sent by the server.
+     */
+    readAll: function() {
+        return this.recv_buf;
+    },
+
+    /**
+     * Sets the send buffer to buf.
+     * @param {string} buf - The buffer to send.
+     */    
+    write: function(buf) {
+        this.send_buf = buf;
+    },
+
+    /**
+     * Returns the send buffer.
+     * @readonly
+     * @returns {string} The send buffer.
+     */ 
+    getSendBuffer: function() {
+        return this.send_buf;
+    }
+
+};
+
+/**
+ * Initializes a Thrift JSON protocol instance.
+ * @constructor
+ * @param {Thrift.Transport} transport - The transport to serialize to/from.
+ * @classdesc Apache Thrift Protocols perform serialization which enables cross 
+ * language RPC. The Protocol type is the JavaScript browser implementation 
+ * of the Apache Thrift TJSONProtocol.
+ * @example
+ *     var protocol  = new Thrift.Protocol(transport);
+ */
+Thrift.Protocol = function(transport) {
+    this.transport = transport;
+};
+
+/**
+ * Thrift IDL type Id to string mapping.
+ * @readonly
+ * @see {@link Thrift.Type}
+ */
+Thrift.Protocol.Type = {};
+Thrift.Protocol.Type[Thrift.Type.BOOL] = '"tf"';
+Thrift.Protocol.Type[Thrift.Type.BYTE] = '"i8"';
+Thrift.Protocol.Type[Thrift.Type.I16] = '"i16"';
+Thrift.Protocol.Type[Thrift.Type.I32] = '"i32"';
+Thrift.Protocol.Type[Thrift.Type.I64] = '"i64"';
+Thrift.Protocol.Type[Thrift.Type.DOUBLE] = '"dbl"';
+Thrift.Protocol.Type[Thrift.Type.STRUCT] = '"rec"';
+Thrift.Protocol.Type[Thrift.Type.STRING] = '"str"';
+Thrift.Protocol.Type[Thrift.Type.MAP] = '"map"';
+Thrift.Protocol.Type[Thrift.Type.LIST] = '"lst"';
+Thrift.Protocol.Type[Thrift.Type.SET] = '"set"';
+
+/**
+ * Thrift IDL type string to Id mapping.
+ * @readonly
+ * @see {@link Thrift.Type}
+ */
+Thrift.Protocol.RType = {};
+Thrift.Protocol.RType.tf = Thrift.Type.BOOL;
+Thrift.Protocol.RType.i8 = Thrift.Type.BYTE;
+Thrift.Protocol.RType.i16 = Thrift.Type.I16;
+Thrift.Protocol.RType.i32 = Thrift.Type.I32;
+Thrift.Protocol.RType.i64 = Thrift.Type.I64;
+Thrift.Protocol.RType.dbl = Thrift.Type.DOUBLE;
+Thrift.Protocol.RType.rec = Thrift.Type.STRUCT;
+Thrift.Protocol.RType.str = Thrift.Type.STRING;
+Thrift.Protocol.RType.map = Thrift.Type.MAP;
+Thrift.Protocol.RType.lst = Thrift.Type.LIST;
+Thrift.Protocol.RType.set = Thrift.Type.SET;
+
+/**
+ * The TJSONProtocol version number.
+ * @readonly
+ * @const {number} Version
+ * @memberof Thrift.Protocol
+ */
+ Thrift.Protocol.Version = 1;
+
+Thrift.Protocol.prototype = {
+    /**
+     * Returns the underlying transport.
+     * @readonly
+     * @returns {Thrift.Transport} The underlying transport.
+     */ 
+    getTransport: function() {
+        return this.transport;
+    },
+
+    /**
+     * Serializes the beginning of a Thrift RPC message.
+     * @param {string} name - The service method to call.
+     * @param {Thrift.MessageType} messageType - The type of method call.
+     * @param {number} seqid - The sequence number of this call (always 0 in Apache Thrift).
+     */
+    writeMessageBegin: function(name, messageType, seqid) {
+        this.tstack = [];
+        this.tpos = [];
+
+        this.tstack.push([Thrift.Protocol.Version, '"' +
+            name + '"', messageType, seqid]);
+    },
+
+    /**
+     * Serializes the end of a Thrift RPC message.
+     */
+    writeMessageEnd: function() {
+        var obj = this.tstack.pop();
+
+        this.wobj = this.tstack.pop();
+        this.wobj.push(obj);
+
+        this.wbuf = '[' + this.wobj.join(',') + ']';
+
+        this.transport.write(this.wbuf);
+     },
+
+
+    /**
+     * Serializes the beginning of a struct.
+     * @param {string} name - The name of the struct.
+     */
+    writeStructBegin: function(name) {
+        this.tpos.push(this.tstack.length);
+        this.tstack.push({});
+    },
+
+    /**
+     * Serializes the end of a struct.
+     */
+    writeStructEnd: function() {
+
+        var p = this.tpos.pop();
+        var struct = this.tstack[p];
+        var str = '{';
+        var first = true;
+        for (var key in struct) {
+            if (first) {
+                first = false;
+            } else {
+                str += ',';
+            }
+
+            str += key + ':' + struct[key];
+        }
+
+        str += '}';
+        this.tstack[p] = str;
+    },
+
+    /**
+     * Serializes the beginning of a struct field.
+     * @param {string} name - The name of the field.
+     * @param {Thrift.Protocol.Type} fieldType - The data type of the field.
+     * @param {number} fieldId - The field's unique identifier.
+     */
+    writeFieldBegin: function(name, fieldType, fieldId) {
+        this.tpos.push(this.tstack.length);
+        this.tstack.push({ 'fieldId': '"' +
+            fieldId + '"', 'fieldType': Thrift.Protocol.Type[fieldType]
+        });
+
+    },
+
+    /**
+     * Serializes the end of a field.
+     */
+    writeFieldEnd: function() {
+        var value = this.tstack.pop();
+        var fieldInfo = this.tstack.pop();
+
+        this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = '{' +
+            fieldInfo.fieldType + ':' + value + '}';
+        this.tpos.pop();
+    },
+
+    /**
+     * Serializes the end of the set of fields for a struct.
+     */
+    writeFieldStop: function() {
+        //na
+    },
+
+    /**
+     * Serializes the beginning of a map collection.
+     * @param {Thrift.Type} keyType - The data type of the key.
+     * @param {Thrift.Type} valType - The data type of the value.
+     * @param {number} [size] - The number of elements in the map (ignored).
+     */
+    writeMapBegin: function(keyType, valType, size) {
+        this.tpos.push(this.tstack.length);
+        this.tstack.push([Thrift.Protocol.Type[keyType],
+            Thrift.Protocol.Type[valType], 0]);
+    },
+
+    /**
+     * Serializes the end of a map.
+     */
+    writeMapEnd: function() {
+        var p = this.tpos.pop();
+
+        if (p == this.tstack.length) {
+            return;
+        }
+
+        if ((this.tstack.length - p - 1) % 2 !== 0) {
+            this.tstack.push('');
+        }
+
+        var size = (this.tstack.length - p - 1) / 2;
+
+        this.tstack[p][this.tstack[p].length - 1] = size;
+
+        var map = '}';
+        var first = true;
+        while (this.tstack.length > p + 1) {
+            var v = this.tstack.pop();
+            var k = this.tstack.pop();
+            if (first) {
+                first = false;
+            } else {
+                map = ',' + map;
+            }
+
+            if (! isNaN(k)) { k = '"' + k + '"'; } //json "keys" need to be strings
+            map = k + ':' + v + map;
+        }
+        map = '{' + map;
+
+        this.tstack[p].push(map);
+        this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
+    },
+
+    /**
+     * Serializes the beginning of a list collection.
+     * @param {Thrift.Type} elemType - The data type of the elements.
+     * @param {number} size - The number of elements in the list.
+     */
+    writeListBegin: function(elemType, size) {
+        this.tpos.push(this.tstack.length);
+        this.tstack.push([Thrift.Protocol.Type[elemType], size]);
+    },
+
+    /**
+     * Serializes the end of a list.
+     */
+    writeListEnd: function() {
+        var p = this.tpos.pop();
+
+        while (this.tstack.length > p + 1) {
+            var tmpVal = this.tstack[p + 1];
+            this.tstack.splice(p + 1, 1);
+            this.tstack[p].push(tmpVal);
+        }
+
+        this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
+    },
+
+    /**
+     * Serializes the beginning of a set collection.
+     * @param {Thrift.Type} elemType - The data type of the elements.
+     * @param {number} size - The number of elements in the list.
+     */
+    writeSetBegin: function(elemType, size) {
+        this.tpos.push(this.tstack.length);
+        this.tstack.push([Thrift.Protocol.Type[elemType], size]);
+    },
+
+    /**
+     * Serializes the end of a set.
+     */
+    writeSetEnd: function() {
+        var p = this.tpos.pop();
+
+        while (this.tstack.length > p + 1) {
+            var tmpVal = this.tstack[p + 1];
+            this.tstack.splice(p + 1, 1);
+            this.tstack[p].push(tmpVal);
+        }
+
+        this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
+    },
+
+    /** Serializes a boolean */
+    writeBool: function(value) {
+        this.tstack.push(value ? 1 : 0);
+    },
+
+    /** Serializes a number */
+    writeByte: function(i8) {
+        this.tstack.push(i8);
+    },
+
+    /** Serializes a number */
+    writeI16: function(i16) {
+        this.tstack.push(i16);
+    },
+
+    /** Serializes a number */
+    writeI32: function(i32) {
+        this.tstack.push(i32);
+    },
+
+    /** Serializes a number */
+    writeI64: function(i64) {
+        this.tstack.push(i64);
+    },
+
+    /** Serializes a number */
+    writeDouble: function(dbl) {
+        this.tstack.push(dbl);
+    },
+
+    /** Serializes a string */
+    writeString: function(str) {
+        // We do not encode uri components for wire transfer:
+        if (str === null) {
+            this.tstack.push(null);
+        } else {
+            // concat may be slower than building a byte buffer
+            var escapedString = '';
+            for (var i = 0; i < str.length; i++) {
+                var ch = str.charAt(i);      // a single double quote: "
+                if (ch === '\"') {
+                    escapedString += '\\\"'; // write out as: \"
+                } else if (ch === '\\') {    // a single backslash: \
+                    escapedString += '\\\\'; // write out as: \\
+                /* Currently escaped forward slashes break TJSONProtocol.
+                 * As it stands, we can simply pass forward slashes into
+                 * our strings across the wire without being escaped.
+                 * I think this is the protocol's bug, not thrift.js
+                 * } else if(ch === '/') {   // a single forward slash: /
+                 *  escapedString += '\\/';  // write out as \/
+                 * }
+                 */
+                } else if (ch === '\b') {    // a single backspace: invisible
+                    escapedString += '\\b';  // write out as: \b"
+                } else if (ch === '\f') {    // a single formfeed: invisible
+                    escapedString += '\\f';  // write out as: \f"
+                } else if (ch === '\n') {    // a single newline: invisible
+                    escapedString += '\\n';  // write out as: \n"
+                } else if (ch === '\r') {    // a single return: invisible
+                    escapedString += '\\r';  // write out as: \r"
+                } else if (ch === '\t') {    // a single tab: invisible
+                    escapedString += '\\t';  // write out as: \t"
+                } else {
+                    escapedString += ch;     // Else it need not be escaped
+                }
+            }
+            this.tstack.push('"' + escapedString + '"');
+        }
+    },
+
+    /** Serializes a string */
+    writeBinary: function(str) {
+        this.writeString(str);
+    },
+
+    /**
+       @class
+       @name AnonReadMessageBeginReturn
+       @property {string} fname - The name of the service method.
+       @property {Thrift.MessageType} mtype - The type of message call.
+       @property {number} rseqid - The sequence number of the message (0 in Thrift RPC).
+     */
+    /** 
+     * Deserializes the beginning of a message. 
+     * @returns {AnonReadMessageBeginReturn}
+     */
+    readMessageBegin: function() {
+        this.rstack = [];
+        this.rpos = [];
+
+        if (typeof jQuery !== 'undefined') {
+            this.robj = jQuery.parseJSON(this.transport.readAll());
+        } else {
+            this.robj = eval(this.transport.readAll());
+        }
+
+        var r = {};
+        var version = this.robj.shift();
+
+        if (version != Thrift.Protocol.Version) {
+            throw 'Wrong thrift protocol version: ' + version;
+        }
+
+        r.fname = this.robj.shift();
+        r.mtype = this.robj.shift();
+        r.rseqid = this.robj.shift();
+
+
+        //get to the main obj
+        this.rstack.push(this.robj.shift());
+
+        return r;
+    },
+
+    /** Deserializes the end of a message. */
+    readMessageEnd: function() {
+    },
+
+    /** 
+     * Deserializes the beginning of a struct. 
+     * @param {string} [name] - The name of the struct (ignored)
+     * @returns {object} - An object with an empty string fname property
+     */    
+    readStructBegin: function(name) {
+        var r = {};
+        r.fname = '';
+
+        //incase this is an array of structs
+        if (this.rstack[this.rstack.length - 1] instanceof Array) {
+            this.rstack.push(this.rstack[this.rstack.length - 1].shift());
+        }
+
+        return r;
+    },
+
+    /** Deserializes the end of a struct. */
+    readStructEnd: function() {
+        if (this.rstack[this.rstack.length - 2] instanceof Array) {
+            this.rstack.pop();
+        }
+    },
+
+    /**
+       @class
+       @name AnonReadFieldBeginReturn
+       @property {string} fname - The name of the field (always '').
+       @property {Thrift.Type} ftype - The data type of the field.
+       @property {number} fid - The unique identifier of the field.
+     */
+    /** 
+     * Deserializes the beginning of a field. 
+     * @returns {AnonReadFieldBeginReturn}
+     */
+    readFieldBegin: function() {
+        var r = {};
+
+        var fid = -1;
+        var ftype = Thrift.Type.STOP;
+
+        //get a fieldId
+        for (var f in (this.rstack[this.rstack.length - 1])) {
+            if (f === null) {
+              continue;
+            }
+
+            fid = parseInt(f, 10);
+            this.rpos.push(this.rstack.length);
+
+            var field = this.rstack[this.rstack.length - 1][fid];
+
+            //remove so we don't see it again
+            delete this.rstack[this.rstack.length - 1][fid];
+
+            this.rstack.push(field);
+
+            break;
+        }
+
+        if (fid != -1) {
+
+            //should only be 1 of these but this is the only
+            //way to match a key
+            for (var i in (this.rstack[this.rstack.length - 1])) {
+                if (Thrift.Protocol.RType[i] === null) {
+                    continue;
+                }
+
+                ftype = Thrift.Protocol.RType[i];
+                this.rstack[this.rstack.length - 1] =
+                    this.rstack[this.rstack.length - 1][i];
+            }
+        }
+
+        r.fname = '';
+        r.ftype = ftype;
+        r.fid = fid;
+
+        return r;
+    },
+
+    /** Deserializes the end of a field. */
+    readFieldEnd: function() {
+        var pos = this.rpos.pop();
+
+        //get back to the right place in the stack
+        while (this.rstack.length > pos) {
+            this.rstack.pop();
+        }
+
+    },
+
+    /**
+       @class
+       @name AnonReadMapBeginReturn
+       @property {Thrift.Type} ktype - The data type of the key.
+       @property {Thrift.Type} vtype - The data type of the value.
+       @property {number} size - The number of elements in the map.
+     */
+    /** 
+     * Deserializes the beginning of a map. 
+     * @returns {AnonReadMapBeginReturn}
+     */
+    readMapBegin: function() {
+        var map = this.rstack.pop();
+
+        var r = {};
+        r.ktype = Thrift.Protocol.RType[map.shift()];
+        r.vtype = Thrift.Protocol.RType[map.shift()];
+        r.size = map.shift();
+
+
+        this.rpos.push(this.rstack.length);
+        this.rstack.push(map.shift());
+
+        return r;
+    },
+
+    /** Deserializes the end of a map. */
+    readMapEnd: function() {
+        this.readFieldEnd();
+    },
+
+    /**
+       @class
+       @name AnonReadColBeginReturn
+       @property {Thrift.Type} etype - The data type of the element.
+       @property {number} size - The number of elements in the collection.
+     */
+    /** 
+     * Deserializes the beginning of a list. 
+     * @returns {AnonReadColBeginReturn}
+     */
+    readListBegin: function() {
+        var list = this.rstack[this.rstack.length - 1];
+
+        var r = {};
+        r.etype = Thrift.Protocol.RType[list.shift()];
+        r.size = list.shift();
+
+        this.rpos.push(this.rstack.length);
+        this.rstack.push(list);
+
+        return r;
+    },
+
+    /** Deserializes the end of a list. */
+    readListEnd: function() {
+        this.readFieldEnd();
+    },
+
+    /** 
+     * Deserializes the beginning of a set. 
+     * @returns {AnonReadColBeginReturn}
+     */
+    readSetBegin: function(elemType, size) {
+        return this.readListBegin(elemType, size);
+    },
+
+    /** Deserializes the end of a set. */
+    readSetEnd: function() {
+        return this.readListEnd();
+    },
+
+    /** Returns an object with a value property set to 
+     *  False unless the next number in the protocol buffer 
+     *  is 1, in which case teh value property is True */
+    readBool: function() {
+        var r = this.readI32();
+
+        if (r !== null && r.value == '1') {
+            r.value = true;
+        } else {
+            r.value = false;
+        }
+
+        return r;
+    },
+
+    /** Returns the an object with a value property set to the 
+        next value found in the protocol buffer */
+    readByte: function() {
+        return this.readI32();
+    },
+
+    /** Returns the an object with a value property set to the 
+        next value found in the protocol buffer */
+    readI16: function() {
+        return this.readI32();
+    },
+
+    /** Returns the an object with a value property set to the 
+        next value found in the protocol buffer */
+    readI32: function(f) {
+        if (f === undefined) {
+            f = this.rstack[this.rstack.length - 1];
+        }
+
+        var r = {};
+
+        if (f instanceof Array) {
+            if (f.length === 0) {
+                r.value = undefined;
+            } else {
+                r.value = f.shift();
+            }
+        } else if (f instanceof Object) {
+           for (var i in f) {
+                if (i === null) {
+                  continue;
+                }
+                this.rstack.push(f[i]);
+                delete f[i];
+
+                r.value = i;
+                break;
+           }
+        } else {
+            r.value = f;
+            this.rstack.pop();
+        }
+
+        return r;
+    },
+
+    /** Returns the an object with a value property set to the 
+        next value found in the protocol buffer */
+    readI64: function() {
+        return this.readI32();
+    },
+
+    /** Returns the an object with a value property set to the 
+        next value found in the protocol buffer */
+    readDouble: function() {
+        return this.readI32();
+    },
+
+    /** Returns the an object with a value property set to the 
+        next value found in the protocol buffer */
+    readString: function() {
+        var r = this.readI32();
+        return r;
+    },
+
+    /** Returns the an object with a value property set to the 
+        next value found in the protocol buffer */
+    readBinary: function() {
+        return this.readString();
+    },
+
+    /** 
+     * Method to arbitrarily skip over data (not implemented).
+     * @throws {string} this method is not implemented and always throws.
+     */
+    skip: function(type) {
+        throw 'skip not supported yet';
+    }
+};

http://git-wip-us.apache.org/repos/asf/thrift/blob/095ddb7f/lib/js/test/build.xml
----------------------------------------------------------------------
diff --git a/lib/js/test/build.xml b/lib/js/test/build.xml
index 53bec58..e302ea0 100755
--- a/lib/js/test/build.xml
+++ b/lib/js/test/build.xml
@@ -100,7 +100,7 @@
     <get src="http://code.jquery.com/qunit/qunit-1.5.0.js" dest="${build}/js/lib/qunit.js" usetimestamp="true"/>
     <get src="http://code.jquery.com/qunit/qunit-1.5.0.css" dest="${build}/js/lib/qunit.css" usetimestamp="true"/>
     <!-- js-test-driver has issues with relative path...so we need a copy -->
-    <copy file="../thrift.js" todir="${build}/js/"/>
+    <copy file="../src/thrift.js" todir="${build}/js/"/>
   </target>
 
   <target name="compile" description="compile the test suite" depends="init, generate, resolve">
@@ -216,7 +216,7 @@
     <jsl:jslint options="evil,forin,browser,bitwise,regexp,newcap,immed" encoding="UTF-8">
       <formatter type="plain" />
       <fileset dir="${genjs}" includes="**/*.js" />
-      <fileset dir=".." includes="thrift.js" />
+      <fileset dir="../src" includes="thrift.js" />
 
       <!-- issues with unsafe character -->
       <!-- fileset dir="." includes="*test*.js" /> -->
@@ -234,7 +234,7 @@
     <exec executable="gjslint" failifexecutionfails="no">
       <arg line="--nojsdoc"/>
       <arg line="${genjs}/*.js"/>
-      <arg line="../thrift.js"/>
+      <arg line="../src/thrift.js"/>
 
       <!-- issues with unsafe character, etc. -->
       <!-- <arg line="*test*.js"/> -->

http://git-wip-us.apache.org/repos/asf/thrift/blob/095ddb7f/lib/js/test/phantomjs-qunit.js
----------------------------------------------------------------------
diff --git a/lib/js/test/phantomjs-qunit.js b/lib/js/test/phantomjs-qunit.js
index d52b522..027be40 100755
--- a/lib/js/test/phantomjs-qunit.js
+++ b/lib/js/test/phantomjs-qunit.js
@@ -1,3 +1,5 @@
+/*jshint evil:true*/
+
 /* This file is only used by the test suite.
  *
  * Origin:  https://github.com/ariya/phantomjs/blob/master/examples/run-qunit.js
@@ -35,12 +37,16 @@ function waitFor(testFx, onReady, timeOutMillis) {
                 } else {
                     // Condition fulfilled (timeout and/or condition is 'true')
                     console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
-                    typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled
+                    if (typeof(onReady) === "string") {
+                        eval(onReady);
+                    } else {
+                        onReady(); //< Do what it's supposed to do once the condition is fulfilled
+                    }  
                     clearInterval(interval); //< Stop this interval
                 }
             }
         }, 100); //< repeat check every 250ms
-};
+}
 
 
 if (phantom.args.length === 0 || phantom.args.length > 2) {

http://git-wip-us.apache.org/repos/asf/thrift/blob/095ddb7f/lib/js/test/test.html
----------------------------------------------------------------------
diff --git a/lib/js/test/test.html b/lib/js/test/test.html
index 1c8fc9a..93894c7 100755
--- a/lib/js/test/test.html
+++ b/lib/js/test/test.html
@@ -22,7 +22,7 @@
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   <title>Thrift Javascript Bindings: Unit Test</title>
 
-  <script src="/thrift.js"                  type="text/javascript" charset="utf-8"></script>
+  <script src="/src/thrift.js"                  type="text/javascript" charset="utf-8"></script>
   <script src="gen-js/ThriftTest_types.js" type="text/javascript" charset="utf-8"></script>
   <script src="gen-js/ThriftTest.js"       type="text/javascript" charset="utf-8"></script>
 

http://git-wip-us.apache.org/repos/asf/thrift/blob/095ddb7f/lib/js/test/test.js
----------------------------------------------------------------------
diff --git a/lib/js/test/test.js b/lib/js/test/test.js
index 99fcc41..b0904a9 100755
--- a/lib/js/test/test.js
+++ b/lib/js/test/test.js
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- 
+ /* jshint -W100 */
  
 /*
  * JavaScript test suite
@@ -401,6 +401,8 @@ module("Async");
     .error(function(xhr, status, e){
       equal(e.errorCode, 1001);
       equal(e.message, "Xception");
-      QUnit.start();
+      //QUnit.start();
+      //Note start is not required here because:
+      //$(document).ajaxError( function() { QUnit.start(); } );
     });
   });

http://git-wip-us.apache.org/repos/asf/thrift/blob/095ddb7f/lib/js/thrift.js
----------------------------------------------------------------------
diff --git a/lib/js/thrift.js b/lib/js/thrift.js
deleted file mode 100644
index e59f07f..0000000
--- a/lib/js/thrift.js
+++ /dev/null
@@ -1,779 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-var Thrift = {
-    Version: '1.0.0-dev',
-/*
-    Description: 'JavaScript bindings for the Apache Thrift RPC system',
-    License: 'http://www.apache.org/licenses/LICENSE-2.0',
-    Homepage: 'http://thrift.apache.org',
-    BugReports: 'https://issues.apache.org/jira/browse/THRIFT',
-    Maintainer: 'dev@thrift.apache.org',
-*/
-
-    Type: {
-        'STOP' : 0,
-        'VOID' : 1,
-        'BOOL' : 2,
-        'BYTE' : 3,
-        'I08' : 3,
-        'DOUBLE' : 4,
-        'I16' : 6,
-        'I32' : 8,
-        'I64' : 10,
-        'STRING' : 11,
-        'UTF7' : 11,
-        'STRUCT' : 12,
-        'MAP' : 13,
-        'SET' : 14,
-        'LIST' : 15,
-        'UTF8' : 16,
-        'UTF16' : 17
-    },
-
-    MessageType: {
-        'CALL' : 1,
-        'REPLY' : 2,
-        'EXCEPTION' : 3
-    },
-
-    objectLength: function(obj) {
-        var length = 0;
-        for (var k in obj) {
-            if (obj.hasOwnProperty(k)) {
-                length++;
-            }
-        }
-
-        return length;
-    },
-
-    inherits: function(constructor, superConstructor) {
-      //Prototypal Inheritance http://javascript.crockford.com/prototypal.html
-      function F() {}
-      F.prototype = superConstructor.prototype;
-      constructor.prototype = new F();
-    }
-};
-
-
-
-Thrift.TException = function(message) {
-    this.message = message;
-};
-Thrift.inherits(Thrift.TException, Error);
-Thrift.TException.prototype.name = 'TException';
-
-Thrift.TApplicationExceptionType = {
-    'UNKNOWN' : 0,
-    'UNKNOWN_METHOD' : 1,
-    'INVALID_MESSAGE_TYPE' : 2,
-    'WRONG_METHOD_NAME' : 3,
-    'BAD_SEQUENCE_ID' : 4,
-    'MISSING_RESULT' : 5,
-    'INTERNAL_ERROR' : 6,
-    'PROTOCOL_ERROR' : 7,
-    'INVALID_TRANSFORM' : 8,
-    'INVALID_PROTOCOL' : 9,
-    'UNSUPPORTED_CLIENT_TYPE' : 10
-};
-
-Thrift.TApplicationException = function(message, code) {
-    this.message = message;
-    this.code = (code === null) ? 0 : code;
-};
-Thrift.inherits(Thrift.TApplicationException, Thrift.TException);
-Thrift.TApplicationException.prototype.name = 'TApplicationException';
-
-Thrift.TApplicationException.prototype.read = function(input) {
-    while (1) {
-        var ret = input.readFieldBegin();
-
-        if (ret.ftype == Thrift.Type.STOP) {
-            break;
-        }
-
-        var fid = ret.fid;
-
-        switch (fid) {
-            case 1:
-                if (ret.ftype == Thrift.Type.STRING) {
-                    ret = input.readString();
-                    this.message = ret.value;
-                } else {
-                    ret = input.skip(ret.ftype);
-                }
-                break;
-            case 2:
-                if (ret.ftype == Thrift.Type.I32) {
-                    ret = input.readI32();
-                    this.code = ret.value;
-                } else {
-                    ret = input.skip(ret.ftype);
-                }
-                break;
-           default:
-                ret = input.skip(ret.ftype);
-                break;
-        }
-
-        input.readFieldEnd();
-    }
-
-    input.readStructEnd();
-};
-
-Thrift.TApplicationException.prototype.write = function(output) {
-    var xfer = 0;
-
-    output.writeStructBegin('TApplicationException');
-
-    if (this.message) {
-        output.writeFieldBegin('message', Thrift.Type.STRING, 1);
-        output.writeString(this.getMessage());
-        output.writeFieldEnd();
-    }
-
-    if (this.code) {
-        output.writeFieldBegin('type', Thrift.Type.I32, 2);
-        output.writeI32(this.code);
-        output.writeFieldEnd();
-    }
-
-    output.writeFieldStop();
-    output.writeStructEnd();
-};
-
-Thrift.TApplicationException.prototype.getCode = function() {
-    return this.code;
-};
-
-Thrift.TApplicationException.prototype.getMessage = function() {
-    return this.message;
-};
-
-/**
- *If you do not specify a url then you must handle ajax on your own.
- *This is how to use js bindings in a async fashion.
- */
-Thrift.Transport = function(url) {
-    this.url = url;
-    this.wpos = 0;
-    this.rpos = 0;
-
-    this.send_buf = '';
-    this.recv_buf = '';
-};
-
-Thrift.Transport.prototype = {
-
-    //Gets the browser specific XmlHttpRequest Object
-    getXmlHttpRequestObject: function() {
-        try { return new XMLHttpRequest(); } catch (e1) { }
-        try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch (e2) { }
-        try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch (e3) { }
-
-        throw "Your browser doesn't support the XmlHttpRequest object.";
-    },
-
-    flush: function(async) {
-        //async mode
-        if (async || this.url === undefined || this.url === '') {
-            return this.send_buf;
-        }
-
-        var xreq = this.getXmlHttpRequestObject();
-
-        if (xreq.overrideMimeType) {
-            xreq.overrideMimeType('application/json');
-        }
-
-        xreq.open('POST', this.url, false);
-        xreq.send(this.send_buf);
-
-        if (xreq.readyState != 4) {
-            throw 'encountered an unknown ajax ready state: ' + xreq.readyState;
-        }
-
-        if (xreq.status != 200) {
-            throw 'encountered a unknown request status: ' + xreq.status;
-        }
-
-        this.recv_buf = xreq.responseText;
-        this.recv_buf_sz = this.recv_buf.length;
-        this.wpos = this.recv_buf.length;
-        this.rpos = 0;
-    },
-
-    jqRequest: function(client, postData, args, recv_method) {
-        if (typeof jQuery === 'undefined' ||
-            typeof jQuery.Deferred === 'undefined') {
-            throw 'Thrift.js requires jQuery 1.5+ to use asynchronous requests';
-        }
-
-        var thriftTransport = this;
-
-        var jqXHR = jQuery.ajax({
-            url: this.url,
-            data: postData,
-            type: 'POST',
-            cache: false,
-            contentType: 'application/json',
-            dataType: 'text thrift',
-            converters: {
-                'text thrift' : function(responseData) {
-                    thriftTransport.setRecvBuffer(responseData);
-                    var value = recv_method.call(client);
-                    return value;
-                }
-            },
-            context: client,
-            success: jQuery.makeArray(args).pop()
-        });
-
-        return jqXHR;
-    },
-
-    setRecvBuffer: function(buf) {
-        this.recv_buf = buf;
-        this.recv_buf_sz = this.recv_buf.length;
-        this.wpos = this.recv_buf.length;
-        this.rpos = 0;
-    },
-
-    isOpen: function() {
-        return true;
-    },
-
-    open: function() {},
-
-    close: function() {},
-
-    read: function(len) {
-        var avail = this.wpos - this.rpos;
-
-        if (avail === 0) {
-            return '';
-        }
-
-        var give = len;
-
-        if (avail < len) {
-            give = avail;
-        }
-
-        var ret = this.read_buf.substr(this.rpos, give);
-        this.rpos += give;
-
-        //clear buf when complete?
-        return ret;
-    },
-
-    readAll: function() {
-        return this.recv_buf;
-    },
-
-    write: function(buf) {
-        this.send_buf = buf;
-    },
-
-    getSendBuffer: function() {
-        return this.send_buf;
-    }
-
-};
-
-
-
-Thrift.Protocol = function(transport) {
-    this.transport = transport;
-};
-
-Thrift.Protocol.Type = {};
-Thrift.Protocol.Type[Thrift.Type.BOOL] = '"tf"';
-Thrift.Protocol.Type[Thrift.Type.BYTE] = '"i8"';
-Thrift.Protocol.Type[Thrift.Type.I16] = '"i16"';
-Thrift.Protocol.Type[Thrift.Type.I32] = '"i32"';
-Thrift.Protocol.Type[Thrift.Type.I64] = '"i64"';
-Thrift.Protocol.Type[Thrift.Type.DOUBLE] = '"dbl"';
-Thrift.Protocol.Type[Thrift.Type.STRUCT] = '"rec"';
-Thrift.Protocol.Type[Thrift.Type.STRING] = '"str"';
-Thrift.Protocol.Type[Thrift.Type.MAP] = '"map"';
-Thrift.Protocol.Type[Thrift.Type.LIST] = '"lst"';
-Thrift.Protocol.Type[Thrift.Type.SET] = '"set"';
-
-
-Thrift.Protocol.RType = {};
-Thrift.Protocol.RType.tf = Thrift.Type.BOOL;
-Thrift.Protocol.RType.i8 = Thrift.Type.BYTE;
-Thrift.Protocol.RType.i16 = Thrift.Type.I16;
-Thrift.Protocol.RType.i32 = Thrift.Type.I32;
-Thrift.Protocol.RType.i64 = Thrift.Type.I64;
-Thrift.Protocol.RType.dbl = Thrift.Type.DOUBLE;
-Thrift.Protocol.RType.rec = Thrift.Type.STRUCT;
-Thrift.Protocol.RType.str = Thrift.Type.STRING;
-Thrift.Protocol.RType.map = Thrift.Type.MAP;
-Thrift.Protocol.RType.lst = Thrift.Type.LIST;
-Thrift.Protocol.RType.set = Thrift.Type.SET;
-
-Thrift.Protocol.Version = 1;
-
-Thrift.Protocol.prototype = {
-
-    getTransport: function() {
-        return this.transport;
-    },
-
-    //Write functions
-    writeMessageBegin: function(name, messageType, seqid) {
-        this.tstack = [];
-        this.tpos = [];
-
-        this.tstack.push([Thrift.Protocol.Version, '"' +
-            name + '"', messageType, seqid]);
-    },
-
-    writeMessageEnd: function() {
-        var obj = this.tstack.pop();
-
-        this.wobj = this.tstack.pop();
-        this.wobj.push(obj);
-
-        this.wbuf = '[' + this.wobj.join(',') + ']';
-
-        this.transport.write(this.wbuf);
-     },
-
-
-    writeStructBegin: function(name) {
-        this.tpos.push(this.tstack.length);
-        this.tstack.push({});
-    },
-
-    writeStructEnd: function() {
-
-        var p = this.tpos.pop();
-        var struct = this.tstack[p];
-        var str = '{';
-        var first = true;
-        for (var key in struct) {
-            if (first) {
-                first = false;
-            } else {
-                str += ',';
-            }
-
-            str += key + ':' + struct[key];
-        }
-
-        str += '}';
-        this.tstack[p] = str;
-    },
-
-    writeFieldBegin: function(name, fieldType, fieldId) {
-        this.tpos.push(this.tstack.length);
-        this.tstack.push({ 'fieldId': '"' +
-            fieldId + '"', 'fieldType': Thrift.Protocol.Type[fieldType]
-        });
-
-    },
-
-    writeFieldEnd: function() {
-        var value = this.tstack.pop();
-        var fieldInfo = this.tstack.pop();
-
-        this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = '{' +
-            fieldInfo.fieldType + ':' + value + '}';
-        this.tpos.pop();
-    },
-
-    writeFieldStop: function() {
-        //na
-    },
-
-    writeMapBegin: function(keyType, valType, size) {
-        //size is invalid, we'll set it on end.
-        this.tpos.push(this.tstack.length);
-        this.tstack.push([Thrift.Protocol.Type[keyType],
-            Thrift.Protocol.Type[valType], 0]);
-    },
-
-    writeMapEnd: function() {
-        var p = this.tpos.pop();
-
-        if (p == this.tstack.length) {
-            return;
-        }
-
-        if ((this.tstack.length - p - 1) % 2 !== 0) {
-            this.tstack.push('');
-        }
-
-        var size = (this.tstack.length - p - 1) / 2;
-
-        this.tstack[p][this.tstack[p].length - 1] = size;
-
-        var map = '}';
-        var first = true;
-        while (this.tstack.length > p + 1) {
-            var v = this.tstack.pop();
-            var k = this.tstack.pop();
-            if (first) {
-                first = false;
-            } else {
-                map = ',' + map;
-            }
-
-            if (! isNaN(k)) { k = '"' + k + '"'; } //json "keys" need to be strings
-            map = k + ':' + v + map;
-        }
-        map = '{' + map;
-
-        this.tstack[p].push(map);
-        this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
-    },
-
-    writeListBegin: function(elemType, size) {
-        this.tpos.push(this.tstack.length);
-        this.tstack.push([Thrift.Protocol.Type[elemType], size]);
-    },
-
-    writeListEnd: function() {
-        var p = this.tpos.pop();
-
-        while (this.tstack.length > p + 1) {
-            var tmpVal = this.tstack[p + 1];
-            this.tstack.splice(p + 1, 1);
-            this.tstack[p].push(tmpVal);
-        }
-
-        this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
-    },
-
-    writeSetBegin: function(elemType, size) {
-        this.tpos.push(this.tstack.length);
-        this.tstack.push([Thrift.Protocol.Type[elemType], size]);
-    },
-
-    writeSetEnd: function() {
-        var p = this.tpos.pop();
-
-        while (this.tstack.length > p + 1) {
-            var tmpVal = this.tstack[p + 1];
-            this.tstack.splice(p + 1, 1);
-            this.tstack[p].push(tmpVal);
-        }
-
-        this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
-    },
-
-    writeBool: function(value) {
-        this.tstack.push(value ? 1 : 0);
-    },
-
-    writeByte: function(i8) {
-        this.tstack.push(i8);
-    },
-
-    writeI16: function(i16) {
-        this.tstack.push(i16);
-    },
-
-    writeI32: function(i32) {
-        this.tstack.push(i32);
-    },
-
-    writeI64: function(i64) {
-        this.tstack.push(i64);
-    },
-
-    writeDouble: function(dbl) {
-        this.tstack.push(dbl);
-    },
-
-    writeString: function(str) {
-        // We do not encode uri components for wire transfer:
-        if (str === null) {
-            this.tstack.push(null);
-        } else {
-            // concat may be slower than building a byte buffer
-            var escapedString = '';
-            for (var i = 0; i < str.length; i++) {
-                var ch = str.charAt(i);      // a single double quote: "
-                if (ch === '\"') {
-                    escapedString += '\\\"'; // write out as: \"
-                } else if (ch === '\\') {    // a single backslash: \
-                    escapedString += '\\\\'; // write out as: \\
-                /* Currently escaped forward slashes break TJSONProtocol.
-                 * As it stands, we can simply pass forward slashes into
-                 * our strings across the wire without being escaped.
-                 * I think this is the protocol's bug, not thrift.js
-                 * } else if(ch === '/') {   // a single forward slash: /
-                 *  escapedString += '\\/';  // write out as \/
-                 * }
-                 */
-                } else if (ch === '\b') {    // a single backspace: invisible
-                    escapedString += '\\b';  // write out as: \b"
-                } else if (ch === '\f') {    // a single formfeed: invisible
-                    escapedString += '\\f';  // write out as: \f"
-                } else if (ch === '\n') {    // a single newline: invisible
-                    escapedString += '\\n';  // write out as: \n"
-                } else if (ch === '\r') {    // a single return: invisible
-                    escapedString += '\\r';  // write out as: \r"
-                } else if (ch === '\t') {    // a single tab: invisible
-                    escapedString += '\\t';  // write out as: \t"
-                } else {
-                    escapedString += ch;     // Else it need not be escaped
-                }
-            }
-            this.tstack.push('"' + escapedString + '"');
-        }
-    },
-
-    writeBinary: function(str) {
-        this.writeString(str);
-    },
-
-
-
-    // Reading functions
-    readMessageBegin: function() {
-        this.rstack = [];
-        this.rpos = [];
-
-        if (typeof jQuery !== 'undefined') {
-            this.robj = jQuery.parseJSON(this.transport.readAll());
-        } else {
-            this.robj = eval(this.transport.readAll());
-        }
-
-        var r = {};
-        var version = this.robj.shift();
-
-        if (version != Thrift.Protocol.Version) {
-            throw 'Wrong thrift protocol version: ' + version;
-        }
-
-        r.fname = this.robj.shift();
-        r.mtype = this.robj.shift();
-        r.rseqid = this.robj.shift();
-
-
-        //get to the main obj
-        this.rstack.push(this.robj.shift());
-
-        return r;
-    },
-
-    readMessageEnd: function() {
-    },
-
-    readStructBegin: function(name) {
-        var r = {};
-        r.fname = '';
-
-        //incase this is an array of structs
-        if (this.rstack[this.rstack.length - 1] instanceof Array) {
-            this.rstack.push(this.rstack[this.rstack.length - 1].shift());
-        }
-
-        return r;
-    },
-
-    readStructEnd: function() {
-        if (this.rstack[this.rstack.length - 2] instanceof Array) {
-            this.rstack.pop();
-        }
-    },
-
-    readFieldBegin: function() {
-        var r = {};
-
-        var fid = -1;
-        var ftype = Thrift.Type.STOP;
-
-        //get a fieldId
-        for (var f in (this.rstack[this.rstack.length - 1])) {
-            if (f === null) {
-              continue;
-            }
-
-            fid = parseInt(f, 10);
-            this.rpos.push(this.rstack.length);
-
-            var field = this.rstack[this.rstack.length - 1][fid];
-
-            //remove so we don't see it again
-            delete this.rstack[this.rstack.length - 1][fid];
-
-            this.rstack.push(field);
-
-            break;
-        }
-
-        if (fid != -1) {
-
-            //should only be 1 of these but this is the only
-            //way to match a key
-            for (var i in (this.rstack[this.rstack.length - 1])) {
-                if (Thrift.Protocol.RType[i] === null) {
-                    continue;
-                }
-
-                ftype = Thrift.Protocol.RType[i];
-                this.rstack[this.rstack.length - 1] =
-                    this.rstack[this.rstack.length - 1][i];
-            }
-        }
-
-        r.fname = '';
-        r.ftype = ftype;
-        r.fid = fid;
-
-        return r;
-    },
-
-    readFieldEnd: function() {
-        var pos = this.rpos.pop();
-
-        //get back to the right place in the stack
-        while (this.rstack.length > pos) {
-            this.rstack.pop();
-        }
-
-    },
-
-    readMapBegin: function() {
-        var map = this.rstack.pop();
-
-        var r = {};
-        r.ktype = Thrift.Protocol.RType[map.shift()];
-        r.vtype = Thrift.Protocol.RType[map.shift()];
-        r.size = map.shift();
-
-
-        this.rpos.push(this.rstack.length);
-        this.rstack.push(map.shift());
-
-        return r;
-    },
-
-    readMapEnd: function() {
-        this.readFieldEnd();
-    },
-
-    readListBegin: function() {
-        var list = this.rstack[this.rstack.length - 1];
-
-        var r = {};
-        r.etype = Thrift.Protocol.RType[list.shift()];
-        r.size = list.shift();
-
-        this.rpos.push(this.rstack.length);
-        this.rstack.push(list);
-
-        return r;
-    },
-
-    readListEnd: function() {
-        this.readFieldEnd();
-    },
-
-    readSetBegin: function(elemType, size) {
-        return this.readListBegin(elemType, size);
-    },
-
-    readSetEnd: function() {
-        return this.readListEnd();
-    },
-
-    readBool: function() {
-        var r = this.readI32();
-
-        if (r !== null && r.value == '1') {
-            r.value = true;
-        } else {
-            r.value = false;
-        }
-
-        return r;
-    },
-
-    readByte: function() {
-        return this.readI32();
-    },
-
-    readI16: function() {
-        return this.readI32();
-    },
-
-    readI32: function(f) {
-        if (f === undefined) {
-            f = this.rstack[this.rstack.length - 1];
-        }
-
-        var r = {};
-
-        if (f instanceof Array) {
-            if (f.length === 0) {
-                r.value = undefined;
-            } else {
-                r.value = f.shift();
-            }
-        } else if (f instanceof Object) {
-           for (var i in f) {
-                if (i === null) {
-                  continue;
-                }
-                this.rstack.push(f[i]);
-                delete f[i];
-
-                r.value = i;
-                break;
-           }
-        } else {
-            r.value = f;
-            this.rstack.pop();
-        }
-
-        return r;
-    },
-
-    readI64: function() {
-        return this.readI32();
-    },
-
-    readDouble: function() {
-        return this.readI32();
-    },
-
-    readString: function() {
-        var r = this.readI32();
-        return r;
-    },
-
-    readBinary: function() {
-        return this.readString();
-    },
-
-
-    //Method to arbitrarily skip over data.
-    skip: function(type) {
-        throw 'skip not supported yet';
-    }
-};