THRIFT-625: Add support for 'Go'; provided by Aalok Shah.



git-svn-id: https://svn.apache.org/repos/asf/thrift/trunk@1072478 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/Makefile.am b/compiler/cpp/Makefile.am
index cbb12f5..faaac25 100644
--- a/compiler/cpp/Makefile.am
+++ b/compiler/cpp/Makefile.am
@@ -114,6 +114,9 @@
 if THRIFT_GEN_javame
 thrift_SOURCES += src/generate/t_javame_generator.cc
 endif
+if THRIFT_GEN_go
+thrift_SOURCES += src/generate/t_go_generator.cc
+endif
 
 thrift_CPPFLAGS = -I$(srcdir)/src
 thrift_CXXFLAGS = -Wall
diff --git a/compiler/cpp/src/generate/t_go_generator.cc b/compiler/cpp/src/generate/t_go_generator.cc
new file mode 100644
index 0000000..6780fc5
--- /dev/null
+++ b/compiler/cpp/src/generate/t_go_generator.cc
@@ -0,0 +1,2980 @@
+/*
+ * 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 cogoright 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 cogo 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.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sstream>
+#include <algorithm>
+#include "t_generator.h"
+#include "platform.h"
+using namespace std;
+
+
+/**
+ * Go code generator.
+ *
+ */
+class t_go_generator : public t_generator {
+ public:
+  t_go_generator(
+      t_program* program,
+      const std::map<std::string, std::string>& parsed_options,
+      const std::string& option_string)
+    : t_generator(program)
+  {
+    std::map<std::string, std::string>::const_iterator iter;
+    out_dir_base_ = "gen-go";
+  }
+
+  /**
+   * Init and close methods
+   */
+
+  void init_generator();
+  void close_generator();
+
+  /**
+   * Program-level generation functions
+   */
+
+  void generate_typedef  (t_typedef*  ttypedef);
+  void generate_enum     (t_enum*     tenum);
+  void generate_const    (t_const*    tconst);
+  void generate_struct   (t_struct*   tstruct);
+  void generate_xception (t_struct*   txception);
+  void generate_service  (t_service*  tservice);
+
+  std::string render_const_value(t_type* type, t_const_value* value, const string& name);
+
+  /**
+   * Struct generation code
+   */
+
+  void generate_go_struct(t_struct* tstruct, bool is_exception);
+  void generate_go_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool is_result=false);
+  void generate_go_struct_reader(std::ofstream& out, t_struct* tstruct, const string& tstruct_name, bool is_result=false);
+  void generate_go_struct_writer(std::ofstream& out, t_struct* tstruct, const string& tstruct_name, bool is_result=false);
+  void generate_go_function_helpers(t_function* tfunction);
+
+  /**
+   * Service-level generation functions
+   */
+
+  void generate_service_helpers   (t_service*  tservice);
+  void generate_service_interface (t_service* tservice);
+  void generate_service_client    (t_service* tservice);
+  void generate_service_remote    (t_service* tservice);
+  void generate_service_server    (t_service* tservice);
+  void generate_process_function  (t_service* tservice, t_function* tfunction);
+
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field        (std::ofstream &out,
+                                          t_field*    tfield,
+                                          bool        declare,
+                                          std::string prefix="",
+                                          std::string err="err",
+                                          bool inclass=false,
+                                          bool coerceData=false);
+
+  void generate_deserialize_struct       (std::ofstream &out,
+                                          t_struct*   tstruct,
+                                          bool        declare,
+                                          std::string prefix="",
+                                          std::string err="err");
+
+  void generate_deserialize_container    (std::ofstream &out,
+                                          t_type*     ttype,
+                                          bool        declare,
+                                          std::string prefix="",
+                                          std::string err="err");
+
+  void generate_deserialize_set_element  (std::ofstream &out,
+                                          t_set*      tset,
+                                          bool        declare,
+                                          std::string prefix="",
+                                          std::string err="err");
+
+  void generate_deserialize_map_element  (std::ofstream &out,
+                                          t_map*      tmap,
+                                          bool        declare,
+                                          std::string prefix="",
+                                          std::string err="err");
+
+  void generate_deserialize_list_element (std::ofstream &out,
+                                          t_list*     tlist,
+                                          bool        declare,
+                                          std::string prefix="",
+                                          std::string err="err");
+
+  void generate_serialize_field          (std::ofstream &out,
+                                          t_field*    tfield,
+                                          std::string prefix="",
+                                          std::string err="err");
+
+  void generate_serialize_struct         (std::ofstream &out,
+                                          t_struct*   tstruct,
+                                          std::string prefix="",
+                                          std::string err="err");
+
+  void generate_serialize_container      (std::ofstream &out,
+                                          t_type*     ttype,
+                                          std::string prefix="",
+                                          std::string err="err");
+
+  void generate_serialize_map_element    (std::ofstream &out,
+                                          t_map*      tmap,
+                                          std::string kiter,
+                                          std::string viter,
+                                          std::string err="err");
+
+  void generate_serialize_set_element    (std::ofstream &out,
+                                          t_set*      tmap,
+                                          std::string iter,
+                                          std::string err="err");
+
+  void generate_serialize_list_element   (std::ofstream &out,
+                                          t_list*     tlist,
+                                          std::string iter,
+                                          std::string err="err");
+
+  void generate_go_docstring         (std::ofstream& out,
+                                          t_struct* tstruct);
+
+  void generate_go_docstring         (std::ofstream& out,
+                                          t_function* tfunction);
+
+  void generate_go_docstring         (std::ofstream& out,
+                                          t_doc*    tdoc,
+                                          t_struct* tstruct,
+                                          const char* subheader);
+
+  void generate_go_docstring         (std::ofstream& out,
+                                          t_doc* tdoc);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string go_autogen_comment();
+  std::string go_package();
+  std::string go_imports();
+  std::string render_includes();
+  std::string render_fastbinary_includes();
+  std::string declare_argument(t_field* tfield);
+  std::string render_field_default_value(t_field* tfield, const string& name);
+  std::string type_name(t_type* ttype);
+  std::string function_signature(t_function* tfunction, std::string prefix="");
+  std::string function_signature_if(t_function* tfunction, std::string prefix="", bool addOsError=false);
+  std::string argument_list(t_struct* tstruct);
+  std::string type_to_enum(t_type* ttype);
+  std::string type_to_go_type(t_type* ttype);
+  std::string type_to_spec_args(t_type* ttype);
+
+  static std::string get_real_go_module(const t_program* program) {
+    std::string real_module = program->get_namespace("go");
+    if (real_module.empty()) {
+      return program->get_name();
+    }
+    return real_module;
+  }
+
+ private:
+  
+  /**
+   * File streams
+   */
+
+  std::ofstream f_types_;
+  std::stringstream f_consts_;
+  std::ofstream f_service_;
+
+  std::string package_name_;
+  std::string package_dir_;
+  
+  static std::string publicize(const std::string& value);
+  static std::string privatize(const std::string& value);
+  static bool can_be_nil(t_type* value);
+
+};
+
+
+std::string t_go_generator::publicize(const std::string& value) {
+  if(value.size() <= 0) return value;
+  std::string value2(value);
+  if(!isupper(value2[0]))
+    value2[0] = toupper(value2[0]);
+  // as long as we are changing things, let's change _ followed by lowercase to capital
+  for(string::size_type i=1; i<value2.size()-1; ++i) {
+    if(value2[i] == '_' && isalpha(value2[i+1])) {
+      value2.replace(i, 2, 1, toupper(value2[i+1]));
+    }
+  }
+  return value2;
+}
+
+std::string t_go_generator::privatize(const std::string& value) {
+  if(value.size() <= 0) return value;
+  std::string value2(value);
+  if(!islower(value2[0])) {
+    value2[0] = tolower(value2[0]);
+  }
+  // as long as we are changing things, let's change _ followed by lowercase to capital
+  for(string::size_type i=1; i<value2.size()-1; ++i) {
+    if(value2[i] == '_' && isalpha(value2[i+1])) {
+      value2.replace(i, 2, 1, toupper(value2[i+1]));
+    }
+  }
+  return value2;
+}
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_go_generator::init_generator() {
+  // Make output directory
+  string module = get_real_go_module(program_);
+  string target = module;
+  package_dir_ = get_out_dir();
+  while (true) {
+    // TODO: Do better error checking here.
+    MKDIR(package_dir_.c_str());
+    if (module.empty()) {
+      break;
+    }
+    string::size_type pos = module.find('.');
+    if (pos == string::npos) {
+      package_dir_ += "/";
+      package_dir_ += module;
+      package_name_ = module;
+      module.clear();
+    } else {
+      package_dir_ += "/";
+      package_dir_ += module.substr(0, pos);
+      module.erase(0, pos+1);
+    }
+  }
+  string::size_type loc;
+  while((loc = target.find(".")) != string::npos) {
+    target.replace(loc, 1, 1, '/');
+  }
+  
+  // Make output file
+  string f_types_name = package_dir_+"/"+"ttypes.go";
+  f_types_.open(f_types_name.c_str());
+  f_consts_ << "func init() {" << endl;
+  
+  vector<t_service*> services = program_->get_services();
+  vector<t_service*>::iterator sv_iter;
+  string f_init_name = package_dir_+"/Makefile";
+  ofstream f_init;
+  f_init.open(f_init_name.c_str());
+  f_init  << 
+    endl <<
+    "include $(GOROOT)/src/Make.inc" << endl << endl <<
+    "all: install" << endl << endl <<
+    "TARG=thriftlib/" << target << endl << endl <<
+    "DIRS=\\" << endl;
+  for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+    f_init << "  " << (*sv_iter)->get_name() << "\\" << endl;
+  }
+  f_init << endl <<
+    "GOFILES=\\" << endl <<
+    "  ttypes.go\\" << endl;
+  //  "   constants.go\\" << endl;
+  for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+    f_init << "  " << (*sv_iter)->get_name() << ".go\\" << endl;
+  }
+  f_init << endl << endl <<
+    "include $(GOROOT)/src/Make.pkg" << endl << endl;
+  f_init.close();
+
+  for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+    string service_dir = package_dir_+"/"+(*sv_iter)->get_name();
+    mkdir(service_dir.c_str(), 0755);
+    string f_init_name = service_dir+"/Makefile";
+    ofstream f_init;
+    f_init.open(f_init_name.c_str());
+    f_init  <<
+      endl <<
+      "include $(GOROOT)/src/Make.inc" << endl << endl <<
+      "all: install" << endl << endl <<
+      "TARG=" << publicize((*sv_iter)->get_name()) << "-remote" << endl << endl <<
+      "DIRS=\\" << endl << endl <<
+      "GOFILES=\\" << endl <<
+      "  " << (*sv_iter)->get_name() << "-remote.go\\" << endl << endl <<
+      "include $(GOROOT)/src/Make.cmd" << endl << endl;
+    f_init.close();
+  }
+
+  // Print header
+  f_types_ <<
+    go_autogen_comment() <<
+    go_package() << 
+    go_imports() <<
+    render_includes() <<
+    render_fastbinary_includes() << endl << endl;
+}
+
+/**
+ * Renders all the imports necessary for including another Thrift program
+ */
+string t_go_generator::render_includes() {
+  const vector<t_program*>& includes = program_->get_includes();
+  string result = "";
+  for (size_t i = 0; i < includes.size(); ++i) {
+    result += "import \"thriftlib/" + get_real_go_module(includes[i]) + "\"\n";
+  }
+  if (includes.size() > 0) {
+    result += "\n";
+  }
+  return result;
+}
+
+/**
+ * Renders all the imports necessary to use the accelerated TBinaryProtocol
+ */
+string t_go_generator::render_fastbinary_includes() {
+  return "";
+}
+
+/**
+ * Autogen'd comment
+ */
+string t_go_generator::go_autogen_comment() {
+  return
+    "/* Autogenerated by Thrift\n"
+    " *\n"
+    " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n"
+    " */\n";
+}
+
+/**
+ * Prints standard thrift package
+ */
+string t_go_generator::go_package() {
+  return
+    string("package ") + package_name_ + ";\n\n";
+}
+
+/**
+ * Prints standard thrift imports
+ */
+string t_go_generator::go_imports() {
+  return
+    string("import (\n"
+           "        \"thrift\"\n"
+//           "        \"strings\"\n"
+           "        \"fmt\"\n"
+           ")\n\n");
+}
+
+/**
+ * Closes the type files
+ */
+void t_go_generator::close_generator() {
+  // Close types file
+  f_consts_ << "}" << endl;
+  f_types_ << f_consts_.str() << endl;
+  f_types_.close();
+  f_consts_.clear();
+}
+
+/**
+ * Generates a typedef. This is not done in go, types are all implicit.
+ *
+ * @param ttypedef The type definition
+ */
+void t_go_generator::generate_typedef(t_typedef* ttypedef) {
+  
+  generate_go_docstring(f_types_, ttypedef);
+  string newTypeDef(publicize(ttypedef->get_symbolic()));
+  string baseType(type_to_go_type(ttypedef->get_type()));
+  if(baseType == newTypeDef)
+    return;
+  f_types_ <<
+    "type " << newTypeDef << " " << baseType << endl << endl;
+}
+
+/**
+ * Generates code for an enumerated type. Done using a class to scope
+ * the values.
+ *
+ * @param tenum The enumeration
+ */
+void t_go_generator::generate_enum(t_enum* tenum) {
+  std::ostringstream to_string_mapping, from_string_mapping;
+  std::string tenum_name(publicize(tenum->get_name()));
+
+  generate_go_docstring(f_types_, tenum);
+  f_types_ <<
+    "type " << tenum_name << " int" << endl <<
+    "const (" << endl;
+  
+  to_string_mapping <<
+    indent() << "func (p " << tenum_name << ") String() string {" << endl <<
+    indent() << "  switch p {" << endl;
+  from_string_mapping <<
+    indent() << "func From" << tenum_name << "String(s string) " << tenum_name << " {" << endl <<
+    indent() << "  switch s {" << endl;
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  int value = -1;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    if ((*c_iter)->has_value()) {
+      value = (*c_iter)->get_value();
+    } else {
+      ++value;
+    }
+    string iter_std_name(escape_string((*c_iter)->get_name()));
+    string iter_name((*c_iter)->get_name());
+    f_types_ <<
+      indent() << "  " << iter_name << ' ' << tenum_name << " = " << value << endl;
+    
+    // Dictionaries to/from string names of enums
+    to_string_mapping <<
+      indent() << "  case " << iter_name << ": return \"" << iter_std_name << "\"" << endl;
+    if(iter_std_name != escape_string(iter_name)) {
+      from_string_mapping <<
+        indent() << "  case \"" << iter_std_name << "\", \"" << escape_string(iter_name) << "\": return " << iter_name << endl;
+    } else {
+      from_string_mapping <<
+        indent() << "  case \"" << iter_std_name << "\": return " << iter_name << endl;
+    }
+  }
+  to_string_mapping <<
+    indent() << "  }" << endl <<
+    indent() << "  return \"\"" << endl <<
+    indent() << "}" << endl;
+  from_string_mapping <<
+    indent() << "  }" << endl <<
+    indent() << "  return " << tenum_name << "(-10000)" << endl <<
+    indent() << "}" << endl;
+
+  f_types_ <<
+    indent() << ")" << endl <<
+    to_string_mapping.str() << endl << from_string_mapping.str() << endl <<
+    indent() << "func (p " << tenum_name << ") Value() int {" << endl <<
+    indent() << "  return int(p)" << endl <<
+    indent() << "}" << endl << endl <<
+    indent() << "func (p " << tenum_name << ") IsEnum() bool {" << endl <<
+    indent() << "  return true" << endl <<
+    indent() << "}" << endl << endl;
+}
+
+/**
+ * Generate a constant value
+ */
+void t_go_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = publicize(tconst->get_name());
+  t_const_value* value = tconst->get_value();
+  
+  if(type->is_base_type() || type->is_enum()) {
+    indent(f_types_) << "const " << name << " = " << render_const_value(type, value, name) << endl;
+  } else {
+    f_types_ <<
+      indent() << "var " << name << " " << " " << type_to_go_type(type) << endl;
+    f_consts_ <<
+      "  " << name << " = " << render_const_value(type, value, name) << endl;
+  }
+}
+
+/**
+ * Prints the value of a constant with the given type. Note that type checking
+ * is NOT performed in this function as it is always run beforehand using the
+ * validate_types method in main.cc
+ */
+string t_go_generator::render_const_value(t_type* type, t_const_value* value, const string& name) {
+  type = get_true_type(type);
+  std::ostringstream out;
+
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_STRING:
+      out << '"' << get_escaped_string(value) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << (value->get_integer() > 0 ? "true" : "false");
+      break;
+    case t_base_type::TYPE_BYTE:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      out << value->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        out << value->get_integer();
+      } else {
+        out << value->get_double();
+      }
+      break;
+    default:
+      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
+    }
+  } else if (type->is_enum()) {
+    indent(out) << value->get_integer();
+  } else if (type->is_struct() || type->is_xception()) {
+    out << 
+      "New" << publicize(type->get_name()) << "()" << endl <<
+      indent() << "{" << endl;
+    indent_up();
+    const vector<t_field*>& fields = ((t_struct*)type)->get_members();
+    vector<t_field*>::const_iterator f_iter;
+    const map<t_const_value*, t_const_value*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      t_type* field_type = NULL;
+      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        if ((*f_iter)->get_name() == v_iter->first->get_string()) {
+          field_type = (*f_iter)->get_type();
+        }
+      }
+      if (field_type == NULL) {
+        throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
+      }
+      if(field_type->is_base_type() || field_type->is_enum()) {
+        out <<
+          indent() << name << "." << publicize(v_iter->first->get_string()) << " = " << render_const_value(field_type, v_iter->second, name) << endl;
+      } else {
+        string k(tmp("k"));
+        string v(tmp("v"));
+        out <<
+          indent() << v << " := " << render_const_value(field_type, v_iter->second, v) << endl <<
+          indent() << name << "." << publicize(v_iter->first->get_string()) << " = " << v << endl;
+      }
+    }
+    indent_down();
+    out <<
+      indent() << "}";
+  } else if (type->is_map()) {
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    const map<t_const_value*, t_const_value*>& val = value->get_map();
+    out << 
+      "thrift.NewTMap(" << type_to_enum(ktype) << ", " << type_to_enum(vtype) << ", " << val.size() << ")" << endl <<
+      indent() << "{" << endl;
+    indent_up();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string k(tmp("k"));
+      string v(tmp("v"));
+      out <<
+        indent() << k << " := " << render_const_value(ktype, v_iter->first, k) << endl <<
+        indent() << v << " := " << render_const_value(vtype, v_iter->second, v) << endl <<
+        indent() << name << ".Set(" << k << ", " << v << ")" << endl;
+    }
+    indent_down();
+    out <<
+      indent() << "}" << endl;
+  } else if (type->is_list()) {
+    t_type* etype = ((t_list*)type)->get_elem_type();
+    const vector<t_const_value*>& val = value->get_list();
+    out <<
+      "thrift.NewTList(" << type_to_enum(etype) << ", " << val.size() << ")" << endl <<
+      indent() << "{" << endl;
+    indent_up();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string v(tmp("v"));
+      out <<
+        indent() << v << " := " << render_const_value(etype, *v_iter, v) << endl <<
+        indent() << name << ".Push(" << v << ")" << endl;
+    }
+    indent_down();
+    out <<
+      indent() << "}" << endl;
+  } else if (type->is_set()) {
+    t_type* etype = ((t_set*)type)->get_elem_type();
+    const vector<t_const_value*>& val = value->get_list();
+    out <<
+      "thrift.NewTSet(" << type_to_enum(etype) << ", " << val.size() << ")" << endl <<
+      indent() << "{" << endl;
+    indent_up();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string v(tmp("v"));
+      out <<
+        indent() << v << " := " << render_const_value(etype, *v_iter, v) << endl <<
+        indent() << name << ".Add(" << v << ")" << endl;
+    }
+    indent_down();
+    out <<
+      indent() << "}" << endl;
+  } else {
+    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
+  }
+
+  return out.str();
+}
+
+/**
+ * Generates a go struct
+ */
+void t_go_generator::generate_struct(t_struct* tstruct) {
+  generate_go_struct(tstruct, false);
+}
+
+/**
+ * Generates a struct definition for a thrift exception. Basically the same
+ * as a struct but extends the Exception class.
+ *
+ * @param txception The struct definition
+ */
+void t_go_generator::generate_xception(t_struct* txception) {
+  generate_go_struct(txception, true);
+}
+
+/**
+ * Generates a go struct
+ */
+void t_go_generator::generate_go_struct(t_struct* tstruct,
+                                        bool is_exception) {
+  generate_go_struct_definition(f_types_, tstruct, is_exception);
+}
+
+/**
+ * Generates a struct definition for a thrift data type.
+ *
+ * @param tstruct The struct definition
+ */
+void t_go_generator::generate_go_struct_definition(ofstream& out,
+                                                   t_struct* tstruct,
+                                                   bool is_exception,
+                                                   bool is_result) {
+
+  const vector<t_field*>& members = tstruct->get_members();
+  const vector<t_field*>& sorted_members = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  generate_go_docstring(out, tstruct);
+  std::string tstruct_name(publicize(tstruct->get_name()));
+  out << 
+    indent() << "type " << tstruct_name << " struct {" << endl <<
+    indent() << "  thrift.TStruct" << endl;
+
+  /*
+     Here we generate the structure specification for the fastbinary codec.
+     These specifications have the following structure:
+     thrift_spec -> tuple of item_spec
+     item_spec -> nil | (tag, type_enum, name, spec_args, default)
+     tag -> integer
+     type_enum -> TType.I32 | TType.STRING | TType.STRUCT | ...
+     name -> string_literal
+     default -> nil  # Handled by __init__
+     spec_args -> nil  # For simple types
+                | (type_enum, spec_args)  # Value type for list/set
+                | (type_enum, spec_args, type_enum, spec_args)
+                  # Key and value for map
+                | (class_name, spec_args_ptr) # For struct/exception
+     class_name -> identifier  # Basically a pointer to the class
+     spec_args_ptr -> expression  # just class_name.spec_args
+
+     TODO(dreiss): Consider making this work for structs with negative tags.
+  */
+
+  // TODO(dreiss): Look into generating an empty tuple instead of nil
+  // for structures with no members.
+  // TODO(dreiss): Test encoding of structs where some inner structs
+  // don't have thrift_spec.
+  indent_up();
+  if (sorted_members.empty() || (sorted_members[0]->get_key() >= 0)) {
+    int sorted_keys_pos = 0;
+    for (m_iter = sorted_members.begin(); m_iter != sorted_members.end(); ++m_iter) {
+
+      for (; sorted_keys_pos != (*m_iter)->get_key(); sorted_keys_pos++) {
+        if (sorted_keys_pos != 0) {
+          indent(out) << "_ interface{} \"" << escape_string((*m_iter)->get_name()) << "\"; // nil # " << sorted_keys_pos << endl;
+        }
+      }
+      t_type* fieldType = (*m_iter)->get_type();
+      string goType(type_to_go_type(fieldType));
+      indent(out) << publicize((*m_iter)->get_name()) << " " 
+                  << goType << " \"" << escape_string((*m_iter)->get_name())
+                  << "\"; // " << sorted_keys_pos
+                  << endl;
+
+      sorted_keys_pos ++;
+    }
+
+  } else {
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      // This fills in default values, as opposed to nulls
+      out <<
+        indent() << publicize((*m_iter)->get_name()) << " " <<
+                    type_to_enum((*m_iter)->get_type()) << endl;
+    }
+  }
+  indent_down();
+  out <<
+    indent() << "}" << endl << endl <<
+    indent() << "func New" << tstruct_name << "() *" << tstruct_name << " {" << endl <<
+    indent() << "  output := &" << tstruct_name << "{" << endl <<
+    indent() << "    TStruct:thrift.NewTStruct(\"" << escape_string(tstruct->get_name()) << "\", []thrift.TField{" << endl;
+  indent_up();
+  indent_up();
+  for(m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    string thrift_name((*m_iter)->get_name());
+    out <<
+      indent() << "thrift.NewTField(\"" << escape_string(thrift_name) << "\", " << type_to_enum((*m_iter)->get_type()) << ", "<< (*m_iter)->get_key() << ")," << endl;
+  }
+  out << 
+    indent() << "})," << endl;
+  indent_down();
+  out <<
+    indent() << "}" << endl <<
+    indent() << "{" << endl;
+  indent_up();
+  
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    // Initialize fields
+    //t_type* type = (*m_iter)->get_type();
+    string fieldName(publicize((*m_iter)->get_name()));
+    string fullFieldName = "output." + fieldName;
+    if ((*m_iter)->get_value() != NULL) {
+      out <<
+        indent() << fullFieldName << " = " <<
+        render_field_default_value(*m_iter, fullFieldName) << endl;
+    }
+  }
+  indent_down();
+  out <<
+    indent() << "}" << endl <<
+    indent() << "return output" << endl;
+  indent_down();
+  out <<
+    indent() << "}" << endl << endl;
+
+  generate_go_struct_reader(out, tstruct, tstruct_name, is_result);
+  generate_go_struct_writer(out, tstruct, tstruct_name, is_result);
+  
+  // Printing utilities so that on the command line thrift
+  // structs look pretty like dictionaries
+  out << 
+    indent() << "func (p *" << tstruct_name << ") TStructName() string {" << endl <<
+    indent() << "  return \"" << escape_string(tstruct_name) << "\"" << endl <<
+    indent() << "}" << endl << endl;
+  
+  out << 
+    indent() << "func (p *" << tstruct_name << ") ThriftName() string {" << endl <<
+    indent() << "  return \"" << escape_string(tstruct->get_name()) << "\"" << endl <<
+    indent() << "}" << endl << endl;
+  
+  out <<
+    indent() << "func (p *" << tstruct_name << ") String() string {" << endl <<
+    indent() << "  if p == nil {" << endl <<
+    indent() << "    return \"<nil>\"" << endl <<
+    indent() << "  }" << endl <<
+    indent() << "  return fmt.Sprintf(\"" << escape_string(tstruct_name) << "(%+v)\", *p)" << endl <<
+    indent() << "}" << endl << endl;
+
+  // Equality and inequality methods that compare by value
+  if(members.size() <= 0) {
+    out <<
+      indent() << "func (p *" << tstruct_name << ") CompareTo(other interface{}) (int, bool) {" << endl <<
+      indent() << "  if other == nil {" << endl <<
+      indent() << "    return 1, true" << endl <<
+      indent() << "  }" << endl <<
+      indent() << "  _, ok := other.(*" << tstruct_name << ")" << endl <<
+      indent() << "  if !ok {" << endl <<
+      indent() << "    return 0, false" << endl <<
+      indent() << "  }" << endl <<
+      indent() << "  return 0, true" << endl <<
+      indent() << "}" << endl << endl;
+  } else {
+    out <<
+      indent() << "func (p *" << tstruct_name << ") CompareTo(other interface{}) (int, bool) {" << endl <<
+      indent() << "  if other == nil {" << endl <<
+      indent() << "    return 1, true" << endl <<
+      indent() << "  }" << endl <<
+      indent() << "  data, ok := other.(*" << tstruct_name << ")" << endl <<
+      indent() << "  if !ok {" << endl <<
+      indent() << "    return 0, false" << endl <<
+      indent() << "  }" << endl;
+    indent_up();
+    for(m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_type* orig_type = (*m_iter)->get_type();
+      t_type* type = get_true_type(orig_type);
+      string field_name(publicize((*m_iter)->get_name()));
+      if(type->is_base_type() || type->is_enum()) {
+        if(type->is_bool()) {
+          out <<
+            indent() << "if cmp := thrift.CompareBool(p." << field_name << ", data." << field_name << "); cmp != 0 {" << endl <<
+            indent() << "  return cmp, true" << endl <<
+            indent() << "}" << endl;
+        } else {
+          out <<
+            indent() << "if p." << field_name << " != data." << field_name << " {" << endl <<
+            indent() << "  if p." << field_name << " < data." << field_name << " {" << endl <<
+            indent() << "    return -1, true" << endl <<
+            indent() << "  }" << endl <<
+            indent() << "  return 1, true" << endl <<
+            indent() << "}" << endl;
+        }
+      } else if(type->is_container() || type->is_struct() || type->is_xception()) {
+        out <<
+          indent() << "if cmp, ok := p." << field_name << ".CompareTo(data." << field_name << "); !ok || cmp != 0 {" << endl <<
+          indent() << "  return cmp, ok" << endl <<
+          indent() << "}" << endl;
+      } else {
+        throw "INVALID TYPE IN generate_go_struct_definition: " + type->get_name();
+      }
+    }
+    indent_down();
+    out << 
+      indent() << "  return 0, true" << endl <<
+      indent() << "}" << endl << endl;
+  }
+  
+  // Equality and inequality methods that compare by value
+  out <<
+    indent() << "func (p *" << tstruct_name << ") AttributeByFieldId(id int) interface{} {" << endl <<
+    indent() << "  switch id {" << endl <<
+    indent() << "  default: return nil" << endl;
+  indent_up();
+  for(m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    string field_name(publicize((*m_iter)->get_name()));
+    out <<
+      indent() << "case " << (*m_iter)->get_key() << ": return p." << field_name << endl;
+  }
+  indent_down();
+  out <<
+    indent() << "  }" << endl <<
+    indent() << "  return nil" << endl <<
+    indent() << "}" << endl << endl;
+  
+  out <<
+    indent() << "func (p *" << tstruct_name << ") TStructFields() thrift.TFieldContainer {" << endl <<
+    indent() << "  return thrift.NewTFieldContainer([]thrift.TField{" << endl;
+  indent_up();
+  indent_up();
+  for(m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    string thrift_name((*m_iter)->get_name());
+    out <<
+      indent() << "thrift.NewTField(\"" << escape_string(thrift_name) << "\", " << type_to_enum((*m_iter)->get_type()) << ", "<< (*m_iter)->get_key() << ")," << endl;
+  }
+  out << 
+    indent() << "})" << endl;
+  indent_down();
+  indent_down();
+  out <<
+    indent() << "}" << endl << endl;
+}
+
+/**
+ * Generates the read method for a struct
+ */
+void t_go_generator::generate_go_struct_reader(ofstream& out,
+                                                t_struct* tstruct,
+                                                const string& tstruct_name,
+                                                bool is_result) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  string escaped_tstruct_name(escape_string(tstruct->get_name()));
+
+  out <<
+    indent() << "func (p *" << tstruct_name << ") Read(iprot thrift.TProtocol) (err thrift.TProtocolException) {" << endl;
+  indent_up();
+
+  out <<
+    indent() << "_, err = iprot.ReadStructBegin()" << endl <<
+    indent() << "if err != nil { return thrift.NewTProtocolExceptionReadStruct(p.ThriftName(), err); }" << endl;
+
+  // Loop over reading in fields
+  indent(out) << "for {" << endl;
+  indent_up();
+
+  // Read beginning field marker
+  out <<
+    indent() << "fieldName, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()" << endl <<
+    indent() << "if fieldId < 0 {" << endl <<
+    indent() << "  fieldId = int16(p.FieldIdFromFieldName(fieldName))" << endl <<
+    indent() << "} else if fieldName == \"\" {" << endl <<
+    indent() << "  fieldName = p.FieldNameFromFieldId(int(fieldId))" << endl <<
+    indent() << "}" << endl <<
+    indent() << "if fieldTypeId == thrift.GENERIC {" << endl <<
+    indent() << "  fieldTypeId = p.FieldFromFieldId(int(fieldId)).TypeId()" << endl <<
+    indent() << "}" << endl <<
+    indent() << "if err != nil {" << endl <<
+    indent() << "  return thrift.NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)" << endl <<
+    indent() << "}" << endl;
+
+  // Check for field STOP marker and break
+  out <<
+    indent() << "if fieldTypeId == thrift.STOP { break; }" << endl;
+
+  // Switch statement on the field we are reading
+  bool first = true;
+
+  // Generate deserialization code for known cases
+  int32_t field_id = -1;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    field_id = (*f_iter)->get_key();
+    if (first) {
+      first = false;
+      indent(out);
+    } else {
+      indent(out) << "} else ";
+    }
+    out << "if fieldId == " << field_id << " || fieldName == \"" << escape_string((*f_iter)->get_name()) << "\" {" << endl;
+    indent_up();
+    out <<
+      indent() << "if fieldTypeId == " << type_to_enum((*f_iter)->get_type()) << " {" << endl <<
+      indent() << "  err = p.ReadField" << field_id << "(iprot)" << endl <<
+      indent() << "  if err != nil { return thrift.NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err); }" << endl <<
+      indent() << "} else if fieldTypeId == thrift.VOID {" << endl <<
+      indent() << "  err = iprot.Skip(fieldTypeId)" << endl <<
+      indent() << "  if err != nil { return thrift.NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err); }" << endl <<
+      indent() << "} else {" << endl <<
+      indent() << "  err = p.ReadField" << field_id << "(iprot)" << endl <<
+      indent() << "  if err != nil { return thrift.NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err); }" << endl <<
+      indent() << "}" << endl;
+    indent_down();
+  }
+
+  // In the default case we skip the field
+  if (first) {
+    out <<
+      indent() << "if {" << endl;
+  } else {
+    out <<
+      indent() << "} else {" << endl;
+  }
+  out <<
+    indent() << "  err = iprot.Skip(fieldTypeId)" << endl <<
+    indent() << "  if err != nil { return thrift.NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err); }" << endl <<
+    indent() << "}" << endl;
+
+  // Read field end marker
+  out <<
+    indent() << "err = iprot.ReadFieldEnd()" << endl <<
+    indent() << "if err != nil { return thrift.NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err); }" << endl;
+
+  indent_down();
+  out <<
+    indent() << "}" << endl <<
+    indent() << "err = iprot.ReadStructEnd()" << endl <<
+    indent() << "if err != nil { return thrift.NewTProtocolExceptionReadStruct(p.ThriftName(), err); }" << endl <<
+    indent() << "return err" << endl;
+
+  indent_down();
+  out <<
+    indent() << "}" << endl << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    string field_type_name(publicize((*f_iter)->get_type()->get_name()));
+    string field_name(publicize((*f_iter)->get_name()));
+    int32_t field_id = (*f_iter)->get_key();
+    out <<
+      indent() << "func (p *" << tstruct_name << ") ReadField" << field_id << "(iprot thrift.TProtocol) (err thrift.TProtocolException) {" << endl;
+    indent_up();
+    generate_deserialize_field(out, *f_iter, false, "p.");
+    indent_down();
+    out <<
+      indent() << "  return err" << endl <<
+      indent() << "}" << endl << endl <<
+      indent() << "func (p *" << tstruct_name << ") ReadField" << field_name << "(iprot thrift.TProtocol) (thrift.TProtocolException) {" << endl <<
+      indent() << "  return p.ReadField" << field_id << "(iprot)" << endl <<
+      indent() << "}" << endl << endl;
+  }
+}
+
+void t_go_generator::generate_go_struct_writer(ofstream& out,
+                                               t_struct* tstruct,
+                                               const string& tstruct_name,
+                                               bool is_result) {
+  string name(tstruct->get_name());
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) <<
+    "func (p *" << tstruct_name << ") Write(oprot thrift.TProtocol) (err thrift.TProtocolException) {" << endl;
+  indent_up();
+
+  out << 
+    indent() << "err = oprot.WriteStructBegin(\"" << name << "\")" << endl <<
+    indent() << "if err != nil { return thrift.NewTProtocolExceptionWriteStruct(" <<
+                          "p.ThriftName(), err); }" << endl;
+  
+  string field_name;
+  string escape_field_name;
+  int32_t fieldId = -1;
+  if (is_result && fields.size()) {
+    out <<
+      indent() << "switch {" << endl;
+    vector<t_field*>::const_reverse_iterator fr_iter;
+    for (fr_iter = fields.rbegin(); fr_iter != fields.rend(); ++fr_iter) {
+      field_name = (*fr_iter)->get_name();
+      fieldId = (*fr_iter)->get_key();
+      if(can_be_nil((*fr_iter)->get_type()) && fieldId != 0) {
+        out <<
+          indent() << "case p." << publicize(field_name) << " != nil:" << endl <<
+          indent() << "  if err = p.WriteField" << fieldId << "(oprot); err != nil {" << endl <<
+          indent() << "    return err" << endl <<
+          indent() << "  }" << endl;
+      } else {
+        out <<
+          indent() << "default:" << endl <<
+          indent() << "  if err = p.WriteField" << fieldId << "(oprot); err != nil {" << endl <<
+          indent() << "    return err" << endl <<
+          indent() << "  }" << endl;
+      }
+    }
+    out <<
+      indent() << "}" << endl;
+  } else {
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      field_name = (*f_iter)->get_name();
+      escape_field_name = escape_string(field_name);
+      fieldId = (*f_iter)->get_key();
+      out <<
+        indent() << "err = p.WriteField" << fieldId << "(oprot)" << endl <<
+        indent() << "if err != nil { return err }" << endl;
+    }
+  }
+
+  // Write the struct map
+  out <<
+    indent() << "err = oprot.WriteFieldStop()" << endl <<
+    indent() << "if err != nil { return thrift.NewTProtocolExceptionWriteField(-1, \"STOP\", p.ThriftName(), err); }" << endl <<
+    indent() << "err = oprot.WriteStructEnd()" << endl <<
+    indent() << "if err != nil { return thrift.NewTProtocolExceptionWriteStruct(" <<
+                          "p.ThriftName(), err); }" << endl <<
+    indent() << "return err" << endl;
+
+  indent_down();
+  out <<
+    indent() << "}" << endl << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    fieldId = (*f_iter)->get_key();
+    field_name = (*f_iter)->get_name();
+    escape_field_name = escape_string(field_name);
+    out <<
+      indent() << "func (p *" << tstruct_name << ") WriteField" << fieldId << "(oprot thrift.TProtocol) (err thrift.TProtocolException) {" << endl;
+    indent_up();
+    // Write field header
+    if (can_be_nil((*f_iter)->get_type())) {
+      out <<
+        indent() << "if p." << publicize(field_name) << " != nil {" << endl;
+      indent_up();
+    }
+    out <<
+      indent() << "err = oprot.WriteFieldBegin(\"" <<
+                            escape_field_name << "\", " <<
+                            type_to_enum((*f_iter)->get_type()) << ", " <<
+                            fieldId << ")" << endl <<
+      indent() << "if err != nil { return thrift.NewTProtocolExceptionWriteField(" <<
+                            fieldId << ", \"" <<
+                            escape_field_name << "\", " <<
+                            "p.ThriftName(), err); }" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "p.");
+    
+    // Write field closer
+    out <<
+      indent() << "err = oprot.WriteFieldEnd()" << endl <<
+      indent() << "if err != nil { return thrift.NewTProtocolExceptionWriteField(" <<
+                            fieldId << ", \"" <<
+                            escape_field_name << "\", " <<
+                            "p.ThriftName(), err); }" << endl;
+
+    if (can_be_nil((*f_iter)->get_type())) {
+      indent_down();
+      out <<
+        indent() << "}" << endl;
+    }
+    indent_down();
+    out <<
+      indent() << "  return err" << endl <<
+      indent() << "}" << endl << endl <<
+      indent() << "func (p *" << tstruct_name << ") WriteField" << publicize(field_name) << "(oprot thrift.TProtocol) (thrift.TProtocolException) {" << endl <<
+      indent() << "  return p.WriteField" << fieldId << "(oprot)" << endl <<
+      indent() << "}" << endl << endl;
+  }
+}
+
+/**
+ * Generates a thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_go_generator::generate_service(t_service* tservice) {
+  string f_service_name = package_dir_+"/"+service_name_+".go";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ <<
+    go_autogen_comment() <<
+    go_package() <<
+    go_imports();
+
+  if (tservice->get_extends() != NULL) {
+    f_service_ <<
+      "import \"thriftlib/" << get_real_go_module(tservice->get_extends()->get_program()) << "\"" << endl;
+  }
+
+  f_service_ <<
+                "import (" << endl <<
+    indent() << "        \"os\"" << endl <<
+    indent() << ")" << endl << endl <<
+    render_fastbinary_includes();
+
+  f_service_ << endl;
+
+  // Generate the three main parts of the service (well, two for now in PHP)
+  generate_service_interface(tservice);
+  generate_service_client(tservice);
+  generate_service_server(tservice);
+  generate_service_helpers(tservice);
+  generate_service_remote(tservice);
+
+  // Close service file
+  f_service_ << endl;
+  f_service_.close();
+}
+
+/**
+ * Generates helper functions for a service.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_go_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  f_service_ <<
+    "// HELPER FUNCTIONS AND STRUCTURES" << endl << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    generate_go_struct_definition(f_service_, ts, false);
+    generate_go_function_helpers(*f_iter);
+  }
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_go_generator::generate_go_function_helpers(t_function* tfunction) {
+  if (true || !tfunction->is_oneway()) {
+    t_struct result(program_, tfunction->get_name() + "_result");
+    t_field success(tfunction->get_returntype(), "success", 0);
+    if (!tfunction->get_returntype()->is_void()) {
+      result.append(&success);
+    }
+
+    t_struct* xs = tfunction->get_xceptions();
+    const vector<t_field*>& fields = xs->get_members();
+    vector<t_field*>::const_iterator f_iter;
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      result.append(*f_iter);
+    }
+    generate_go_struct_definition(f_service_, &result, false, true);
+  }
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_go_generator::generate_service_interface(t_service* tservice) {
+  string extends = "";
+  string extends_if = "";
+  string serviceName(publicize(tservice->get_name()));
+  string interfaceName = "I" + serviceName;
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    size_t index = extends.rfind(".");
+    if(index != string::npos) {
+      extends_if = "\n" + indent() + "  " + extends.substr(0, index + 1) + "I" + publicize(extends.substr(index + 1)) + "\n";
+    } else {
+      extends_if = "\n" + indent() + "I" + publicize(extends) + "\n";
+    }
+  }
+
+  f_service_ <<
+    indent() << "type " << interfaceName << " interface {" << extends_if;
+  indent_up();
+  generate_go_docstring(f_service_, tservice);
+  vector<t_function*> functions = tservice->get_functions();
+  if (!functions.empty()) {
+    f_service_ << endl;
+    vector<t_function*>::iterator f_iter;
+    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+      generate_go_docstring(f_service_, (*f_iter));
+      f_service_ <<
+        indent() << function_signature_if(*f_iter, "", true) << endl;
+    }
+  }
+
+  indent_down();
+  f_service_ <<
+    indent() << "}" << endl << endl;
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_go_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_client = "";
+  string extends_client_new = "";
+  string serviceName(publicize(tservice->get_name()));
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    size_t index = extends.rfind(".");
+    if(index != string::npos) {
+      extends_client = extends.substr(0, index + 1) + publicize(extends.substr(index + 1)) + "Client";
+      extends_client_new = extends.substr(0, index + 1) + "New" + publicize(extends.substr(index + 1)) + "Client";
+    } else {
+      extends_client = publicize(extends) + "Client";
+      extends_client_new = "New" + extends_client;
+    }
+  }
+
+  generate_go_docstring(f_service_, tservice);
+  f_service_ <<
+    indent() << "type " << serviceName << "Client struct {" << endl;
+  indent_up();
+  if(!extends_client.empty()) {
+    f_service_ << 
+      indent() << "*" << extends_client << endl;
+  } else {
+    f_service_ <<
+      indent() << "Transport thrift.TTransport" << endl <<
+      indent() << "ProtocolFactory thrift.TProtocolFactory" << endl <<
+      indent() << "InputProtocol thrift.TProtocol" << endl <<
+      indent() << "OutputProtocol thrift.TProtocol" << endl <<
+      indent() << "SeqId int32" << endl /*<<
+      indent() << "reqs map[int32]Deferred" << endl*/;
+  }
+  indent_down();
+  f_service_ <<
+    indent() << "}" << endl << endl;
+  
+  // Constructor function
+  f_service_ <<
+    indent() << "func New" << serviceName << "ClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *" << serviceName << "Client {" << endl;
+  indent_up();
+  f_service_ <<
+    indent() << "return &" << serviceName << "Client";
+  if (!extends.empty()) {
+    f_service_ << 
+      "{" << extends_client << ": " << extends_client_new << "Factory(t, f)}";
+  } else {
+    indent_up();
+    f_service_ << "{Transport: t," << endl <<
+      indent() << "ProtocolFactory: f," << endl <<
+      indent() << "InputProtocol: f.GetProtocol(t)," << endl <<
+      indent() << "OutputProtocol: f.GetProtocol(t)," << endl <<
+      indent() << "SeqId: 0," << endl /*<<
+      indent() << "Reqs: make(map[int32]Deferred)" << endl*/;
+    indent_down();
+    f_service_ <<
+      indent() << "}" << endl;
+  }
+  indent_down();
+  f_service_ <<
+    indent() << "}" << endl << endl;
+  
+  
+  // Constructor function
+  f_service_ <<
+    indent() << "func New" << serviceName << "ClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *" << serviceName << "Client {" << endl;
+  indent_up();
+  f_service_ <<
+    indent() << "return &" << serviceName << "Client";
+  if (!extends.empty()) {
+    f_service_ << 
+      "{" << extends_client << ": " << extends_client_new << "Protocol(t, iprot, oprot)}" << endl;
+  } else {
+    indent_up();
+    f_service_ << "{Transport: t," << endl <<
+      indent() << "ProtocolFactory: nil," << endl <<
+      indent() << "InputProtocol: iprot," << endl <<
+      indent() << "OutputProtocol: oprot," << endl <<
+      indent() << "SeqId: 0," << endl /*<<
+      indent() << "Reqs: make(map[int32]interface{})" << endl*/;
+    indent_down();
+    f_service_ <<
+      indent() << "}" << endl;
+  }
+  indent_down();
+  f_service_ <<
+    indent() << "}" << endl << endl;
+
+  // Generate client method implementations
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::const_iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    string funname = publicize((*f_iter)->get_name());
+
+    // Open function
+    generate_go_docstring(f_service_, (*f_iter));
+    f_service_ <<
+      indent() << "func (p *" << serviceName << "Client) " << function_signature_if(*f_iter, "", true) << " {" << endl;
+    indent_up();
+    /*
+    f_service_ <<
+      indent() << "p.SeqId += 1" << endl;
+    if (!(*f_iter)->is_oneway()) {
+      f_service_ <<
+        indent() << "d := defer.Deferred()" << endl <<
+        indent() << "p.Reqs[p.SeqId] = d" << endl;
+    }
+    */
+    f_service_ <<
+      indent() << "err = p.Send" << funname << "(";
+
+    bool first = true;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      if (first) {
+        first = false;
+      } else {
+        f_service_ << ", ";
+      }
+      f_service_ << (*fld_iter)->get_name();
+    }
+    f_service_ << ")" << endl <<
+      indent() << "if err != nil { return }" << endl;
+    
+
+    if (!(*f_iter)->is_oneway()) {
+      f_service_ << 
+        indent() << "return p.Recv" << funname << "()" << endl;
+    } else {
+      f_service_ <<
+        indent() << "return" << endl;
+    }
+    indent_down();
+    f_service_ << 
+      indent() << "}" << endl << endl <<
+      indent() << "func (p *" << serviceName << "Client) Send" << function_signature(*f_iter) << "(err os.Error) {" << endl;
+    
+    indent_up();
+    
+    std::string argsname = privatize((*f_iter)->get_name()) + "Args";
+    
+    // Serialize the request header
+    string args(tmp("args"));
+    f_service_ <<
+      indent() << "oprot := p.OutputProtocol" << endl <<
+      indent() << "if oprot != nil {" << endl <<
+      indent() << "  oprot = p.ProtocolFactory.GetProtocol(p.Transport)" << endl <<
+      indent() << "  p.OutputProtocol = oprot" << endl <<
+      indent() << "}" << endl <<
+      indent() << "p.SeqId++" << endl <<
+      indent() << "oprot.WriteMessageBegin(\"" << (*f_iter)->get_name() << "\", thrift.CALL, p.SeqId)" << endl <<
+      indent() << args << " := New" << publicize(argsname) << "()" << endl;
+    
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ <<
+        indent() << args << "." << publicize((*fld_iter)->get_name()) << " = " << (*fld_iter)->get_name() << endl;
+    }
+    
+    // Write to the stream
+    f_service_ <<
+      indent() << "err = " << args << ".Write(oprot)" << endl <<
+      indent() << "oprot.WriteMessageEnd()" << endl <<
+      indent() << "oprot.Transport().Flush()" << endl <<
+      indent() << "return" << endl;
+    indent_down();
+    f_service_ <<
+      indent() << "}" << endl << endl;
+    
+    if (true) { //!(*f_iter)->is_oneway() || true) {}
+      std::string resultname = privatize((*f_iter)->get_name()) + "Result";
+      // Open function
+      f_service_ << endl <<
+                    indent() << "func (p *" << serviceName << "Client) Recv" << publicize((*f_iter)->get_name()) <<
+                    "() (";
+      if(!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ <<
+          "value " << type_to_go_type((*f_iter)->get_returntype()) << ", ";
+      }
+      t_struct* exceptions = (*f_iter)->get_xceptions();
+      string errs = argument_list(exceptions);
+      if(errs.size()) {
+        f_service_ << errs << ", ";
+      }
+      f_service_ << 
+        "err os.Error) {" << endl;
+      indent_up();
+
+      // TODO(mcslee): Validate message reply here, seq ids etc.
+      
+      string result(tmp("result"));
+      string error(tmp("error"));
+      string error2(tmp("error"));
+      
+      f_service_ <<
+        indent() << "iprot := p.InputProtocol" << endl <<
+        indent() << "if iprot == nil {" << endl <<
+        indent() << "  iprot = p.ProtocolFactory.GetProtocol(p.Transport)" << endl <<
+        indent() << "  p.InputProtocol = iprot" << endl <<
+        indent() << "}" << endl <<
+        indent() << "_, mTypeId, seqId, err := iprot.ReadMessageBegin()" << endl <<
+        indent() << "if err != nil {" << endl <<
+        indent() << "  return" << endl <<
+        indent() << "}" << endl <<
+        indent() << "if mTypeId == thrift.EXCEPTION {" << endl <<
+        indent() << "  " << error << " := thrift.NewTApplicationExceptionDefault()" << endl <<
+        indent() << "  " << error2 << ", err := " << error << ".Read(iprot)" << endl <<
+        indent() << "  if err != nil {" << endl <<
+        indent() << "    return" << endl <<
+        indent() << "  }" << endl <<
+        indent() << "  if err = iprot.ReadMessageEnd(); err != nil {" << endl <<
+        indent() << "    return" << endl <<
+        indent() << "  }" << endl <<
+        indent() << "  err = " << error2 << endl <<
+        indent() << "  return" << endl <<
+        indent() << "}" << endl <<
+        indent() << "if p.SeqId != seqId {" << endl <<
+        indent() << "  err = thrift.NewTApplicationException(thrift.BAD_SEQUENCE_ID, \"ping failed: out of sequence response\")" << endl <<
+        indent() << "  return" << endl <<
+        indent() << "}" << endl <<
+        indent() << result << " := New" << publicize(resultname) << "()" << endl <<
+        indent() << "err = " << result << ".Read(iprot)" << endl <<
+        indent() << "iprot.ReadMessageEnd()" << endl;
+
+      // Careful, only return _result if not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ <<
+          indent() << "value = " << result << ".Success" << endl;
+      }
+      
+      t_struct* xs = (*f_iter)->get_xceptions();
+      const std::vector<t_field*>& xceptions = xs->get_members();
+      vector<t_field*>::const_iterator x_iter;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        f_service_ <<
+          indent() << "if " << result << "." << publicize((*x_iter)->get_name()) << " != nil {" << endl <<
+          indent() << "  " << (*x_iter)->get_name() << " = " << result << "." << publicize((*x_iter)->get_name()) << endl <<
+          indent() << "}" << endl;
+      }
+      
+      f_service_ <<
+        indent() << "return" << endl;
+      // Close function
+      indent_down();
+      f_service_ <<
+        indent() << "}" << endl << endl;
+    }
+  }
+
+  //indent_down();
+  f_service_ <<
+    endl;
+}
+
+/**
+ * Generates a command line tool for making remote requests
+ *
+ * @param tservice The service to generate a remote for.
+ */
+void t_go_generator::generate_service_remote(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  string f_remote_name = package_dir_+"/"+service_name_+"/"+service_name_+"-remote.go";
+  ofstream f_remote;
+  f_remote.open(f_remote_name.c_str());
+  string service_module = get_real_go_module(program_);
+  string::size_type loc;
+  while((loc = service_module.find(".")) != string::npos) {
+    service_module.replace(loc, 1, 1, '/');
+  }
+
+  f_remote <<
+    go_autogen_comment() <<
+    indent() << "package main" << endl << endl <<
+    indent() << "import (" << endl <<
+    indent() << "        \"flag\"" << endl <<
+    indent() << "        \"fmt\"" << endl <<
+    indent() << "        \"http\"" << endl <<
+    indent() << "        \"net\"" << endl <<
+    indent() << "        \"os\"" << endl <<
+    indent() << "        \"strconv\"" << endl <<
+    indent() << "        \"thrift\"" << endl <<
+    indent() << "        \"thriftlib/" << service_module << "\"" << endl <<
+    indent() << ")" << endl <<
+    indent() << endl <<
+    indent() << "func Usage() {" << endl <<
+    indent() << "  fmt.Fprint(os.Stderr, \"Usage of \", os.Args[0], \" [-h host:port] [-u url] [-f[ramed]] function [arg1 [arg2...]]:\\n\")" << endl <<
+    indent() << "  flag.PrintDefaults()" << endl <<
+    indent() << "  fmt.Fprint(os.Stderr, \"Functions:\\n\")" << endl;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string funcName((*f_iter)->get_name());
+    string funcSignature(function_signature_if(*f_iter, "", true));
+    f_remote <<
+      indent() << "  fmt.Fprint(os.Stderr, \"  " << funcName << funcSignature.substr(funcSignature.find("(")) << "\\n\")" << endl;
+  }
+  f_remote <<
+    indent() << "  fmt.Fprint(os.Stderr, \"\\n\")" << endl <<
+    indent() << "  os.Exit(0)" << endl <<
+    indent() << "}" << endl <<
+    indent() << endl <<
+    indent() << "func main() {" << endl;
+  indent_up();
+  f_remote <<
+    indent() << "flag.Usage = Usage" << endl <<
+    indent() << "var host string" << endl <<
+    indent() << "var port int" << endl <<
+    indent() << "var protocol string" << endl <<
+    indent() << "var urlString string" << endl <<
+    indent() << "var framed bool" << endl <<
+    indent() << "var useHttp bool" << endl <<
+    indent() << "var help bool" << endl <<
+    indent() << "var url http.URL" << endl <<
+    indent() << "var trans thrift.TTransport" << endl <<
+    indent() << "flag.Usage = Usage" << endl <<
+    indent() << "flag.StringVar(&host, \"h\", \"localhost\", \"Specify host and port\")" << endl <<
+    indent() << "flag.IntVar(&port, \"p\", 9090, \"Specify port\")" << endl <<
+    indent() << "flag.StringVar(&protocol, \"P\", \"binary\", \"Specify the protocol (binary, compact, simplejson, json)\")" << endl <<
+    indent() << "flag.StringVar(&urlString, \"u\", \"\", \"Specify the url\")" << endl <<
+    indent() << "flag.BoolVar(&framed, \"framed\", false, \"Use framed transport\")" << endl <<
+    indent() << "flag.BoolVar(&useHttp, \"http\", false, \"Use http\")" << endl <<
+    indent() << "flag.BoolVar(&help, \"help\", false, \"See usage string\")" << endl <<
+    indent() << "flag.Parse()" << endl <<
+    indent() << "if help || flag.NArg() == 0 {" << endl <<
+    indent() << "  flag.Usage()" << endl <<
+    indent() << "}" << endl <<
+    indent() << endl <<
+    indent() << "if len(urlString) > 0 {" << endl <<
+    indent() << "  url, err := http.ParseURL(urlString)" << endl <<
+    indent() << "  if err != nil {" << endl <<
+    indent() << "    fmt.Fprint(os.Stderr, \"Error parsing URL: \", err.String(), \"\\n\")" << endl <<
+    indent() << "    flag.Usage()" << endl <<
+    indent() << "  }" << endl <<
+    indent() << "  host = url.Host" << endl <<
+    //indent() << "  if len(url.Port) == 0 { url.Port = \"80\"; }" << endl <<
+    //indent() << "  port = int(url.Port)" << endl <<
+    indent() << "  useHttp = len(url.Scheme) <= 0 || url.Scheme == \"http\"" << endl <<
+    indent() << "} else if useHttp {" << endl <<
+    indent() << "  _, err := http.ParseURL(fmt.Sprint(\"http://\", host, \":\", port))" << endl <<
+    indent() << "  if err != nil {" << endl <<
+    indent() << "    fmt.Fprint(os.Stderr, \"Error parsing URL: \", err.String(), \"\\n\")" << endl <<
+    indent() << "    flag.Usage()" << endl <<
+    indent() << "  }" << endl <<
+    indent() << "}" << endl <<
+    indent() << endl <<
+    indent() << "cmd := flag.Arg(0)" << endl <<
+    indent() << "var err os.Error" << endl <<
+    indent() << "if useHttp {" << endl <<
+    indent() << "  trans, err = thrift.NewTHttpClient(url.Raw)" << endl <<
+    indent() << "} else {" << endl <<
+    indent() << "  addr, err := net.ResolveTCPAddr(fmt.Sprint(host, \":\", port))" << endl <<
+    indent() << "  if err != nil {" << endl <<
+    indent() << "    fmt.Fprint(os.Stderr, \"Error resolving address\", err.String())" << endl <<
+    indent() << "    os.Exit(1)" << endl <<
+    indent() << "  }" << endl <<
+    indent() << "  trans, err = thrift.NewTNonblockingSocketAddr(addr)" << endl <<
+    indent() << "  if framed {" << endl <<
+    indent() << "    trans = thrift.NewTFramedTransport(trans)" << endl <<
+    indent() << "  }" << endl <<
+    indent() << "}" << endl <<
+    indent() << "if err != nil {" << endl <<
+    indent() << "  fmt.Fprint(os.Stderr, \"Error creating transport\", err.String())" << endl <<
+    indent() << "  os.Exit(1)" << endl <<
+    indent() << "}" << endl <<
+    indent() << "defer trans.Close()" << endl <<
+    indent() << "var protocolFactory thrift.TProtocolFactory" << endl <<
+    indent() << "switch protocol {" << endl <<
+    indent() << "case \"compact\":" << endl <<
+    indent() << "  protocolFactory = thrift.NewTCompactProtocolFactory()" << endl <<
+    indent() << "  break" << endl <<
+    indent() << "case \"simplejson\":" << endl <<
+    indent() << "  protocolFactory = thrift.NewTSimpleJSONProtocolFactory()" << endl <<
+    indent() << "  break" << endl <<
+    indent() << "case \"json\":" << endl <<
+    indent() << "  protocolFactory = thrift.NewTJSONProtocolFactory()" << endl <<
+    indent() << "  break" << endl <<
+    indent() << "case \"binary\", \"\":" << endl <<
+    indent() << "  protocolFactory = thrift.NewTBinaryProtocolFactoryDefault()" << endl <<
+    indent() << "  break" << endl <<
+    indent() << "default:" << endl <<
+    indent() << "  fmt.Fprint(os.Stderr, \"Invalid protocol specified: \", protocol, \"\\n\")" << endl <<
+    indent() << "  Usage()" << endl <<
+    indent() << "  os.Exit(1)" << endl <<
+    indent() << "}" << endl <<
+    indent() << "client := " << package_name_ << ".New" << publicize(service_name_) << "ClientFactory(trans, protocolFactory)" << endl <<
+    indent() << "if err = trans.Open(); err != nil {" << endl <<
+    indent() << "  fmt.Fprint(os.Stderr, \"Error opening socket to \", host, \":\", port, \" \", err.String())" << endl <<
+    indent() << "  os.Exit(1)" << endl <<
+    indent() << "}" << endl <<
+    indent() << endl <<
+    indent() << "switch cmd {" << endl;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    const std::vector<t_field*>& args = arg_struct->get_members();
+    vector<t_field*>::const_iterator a_iter;
+    int num_args = args.size();
+    string funcName((*f_iter)->get_name());
+    string pubName(publicize(funcName));
+    
+    f_remote <<
+      indent() << "case \"" << escape_string(funcName) << "\":" << endl;
+    indent_up();
+    f_remote <<
+      indent() << "if flag.NArg() - 1 != " << num_args << " {" << endl <<
+      indent() << "  fmt.Fprint(os.Stderr, \"" << escape_string(pubName) << " requires " << num_args << " args\\n\")" << endl <<
+      indent() << "  flag.Usage()" << endl <<
+      indent() << "}" << endl;
+    for (int i = 0; i < num_args; ++i) {
+      int flagArg = i + 1;
+      t_type* the_type(args[i]->get_type());
+      t_type* the_type2(get_true_type(the_type));
+      if(the_type2->is_enum()) {
+        f_remote << 
+          indent() << "tmp" << i << ", err := (strconv.Atoi(flag.Arg(" << flagArg << ")))" << endl <<
+          indent() << "if err != nil {" << endl <<
+          indent() << "  Usage()" << endl <<
+          indent() << " return" << endl <<
+          indent() << "}" << endl <<
+          indent() << "argvalue" << i << " := " << package_name_ << "." << publicize(the_type->get_name()) << "(tmp" << i << ")" << endl;
+      } else if(the_type2->is_base_type()) {
+        t_base_type::t_base e = ((t_base_type*)the_type2)->get_base();
+        string err(tmp("err"));
+        switch(e) {
+          case t_base_type::TYPE_VOID: break;
+          case t_base_type::TYPE_STRING:
+            f_remote << 
+              indent() << "argvalue" << i << " := flag.Arg(" << flagArg << ")" << endl;
+            break;
+          case t_base_type::TYPE_BOOL:
+            f_remote << 
+              indent() << "argvalue" << i << " := flag.Arg(" << flagArg << ") == \"true\"" << endl;
+            break;
+          case t_base_type::TYPE_BYTE:
+            f_remote << 
+              indent() << "tmp" << i << ", " << err << " := (strconv.Atoi(flag.Arg(" << flagArg << ")))" << endl <<
+              indent() << "if " << err << " != nil {" << endl <<
+              indent() << "  Usage()" << endl <<
+              indent() << "  return" << endl <<
+              indent() << "}" << endl <<
+              indent() << "argvalue" << i << " := byte(tmp" << i << ")" << endl;
+            break;
+          case t_base_type::TYPE_I16:
+            f_remote << 
+              indent() << "tmp" << i << ", " << err << " := (strconv.Atoi(flag.Arg(" << flagArg << ")))" << endl <<
+              indent() << "if " << err << " != nil {" << endl <<
+              indent() << "  Usage()" << endl <<
+              indent() << "  return" << endl <<
+              indent() << "}" << endl <<
+              indent() << "argvalue" << i << " := byte(tmp" << i << ")" << endl;
+            break;
+          case t_base_type::TYPE_I32:
+            f_remote << 
+              indent() << "tmp" << i << ", " << err << " := (strconv.Atoi(flag.Arg(" << flagArg << ")))" << endl <<
+              indent() << "if " << err << " != nil {" << endl <<
+              indent() << "  Usage()" << endl <<
+              indent() << "  return" << endl <<
+              indent() << "}" << endl <<
+              indent() << "argvalue" << i << " := int32(tmp" << i << ")" << endl;
+            break;
+          case t_base_type::TYPE_I64:
+            f_remote <<
+              indent() << "argvalue" << i << ", " << err << " := (strconv.Atoi64(flag.Arg(" << flagArg << ")))" << endl <<
+              indent() << "if " << err << " != nil {" << endl <<
+              indent() << "  Usage()" << endl <<
+              indent() << "  return" << endl <<
+              indent() << "}" << endl;
+            break;
+          case t_base_type::TYPE_DOUBLE:
+            f_remote <<
+              indent() << "argvalue" << i << ", " << err << " := (strconv.Atof64(flag.Arg(" << flagArg << ")))" << endl <<
+              indent() << "if " << err << " != nil {" << endl <<
+              indent() << "  Usage()" << endl <<
+              indent() << "  return" << endl <<
+              indent() << "}" << endl;
+            break;
+          default:
+            throw("Invalid base type in generate_service_remote");
+        }
+        //f_remote << publicize(args[i]->get_name()) << "(strconv.Atoi(flag.Arg(" << flagArg << ")))";
+      } else if(the_type2->is_struct()) {
+        string arg(tmp("arg"));
+        string mbTrans(tmp("mbTrans"));
+        string err1(tmp("err"));
+        string factory(tmp("factory"));
+        string jsProt(tmp("jsProt"));
+        string err2(tmp("err"));
+        std::string tstruct_name(publicize(the_type->get_name()));
+        f_remote <<
+          indent() << arg << " := flag.Arg(" << flagArg << ")" << endl <<
+          indent() << mbTrans << " := thrift.NewTMemoryBufferLen(len(" << arg << "))" << endl <<
+          indent() << "defer " << mbTrans << ".Close()" << endl <<
+          indent() << "_, " << err1 << " := " << mbTrans << ".WriteString(" << arg << ")" << endl <<
+          indent() << "if " << err1 << " != nil {" << endl <<
+          indent() << "  Usage()" << endl <<
+          indent() << "  return" << endl <<
+          indent() << "}" << endl <<
+          indent()  << factory << " := thrift.NewTSimpleJSONProtocolFactory()" << endl <<
+          indent() << jsProt << " := " << factory << ".GetProtocol(" << mbTrans << ")" << endl <<
+          indent() << "argvalue" << i << " := " << package_name_ << ".New" << tstruct_name << "()" << endl <<
+          indent() << err2 << " := argvalue" << i << ".Read(" << jsProt << ")" << endl <<
+          indent() << "if " << err2 << " != nil {" << endl <<
+          indent() << "  Usage()" << endl <<
+          indent() << "  return" << endl <<
+          indent() << "}" << endl;
+      } else if(the_type2->is_container() || the_type2->is_xception()) {
+        string arg(tmp("arg"));
+        string mbTrans(tmp("mbTrans"));
+        string err1(tmp("err"));
+        string factory(tmp("factory"));
+        string jsProt(tmp("jsProt"));
+        string err2(tmp("err"));
+        std::string argName(publicize(args[i]->get_name()));
+        f_remote <<
+          indent() << arg << " := flag.Arg(" << flagArg << ")" << endl <<
+          indent() << mbTrans << " := thrift.NewTMemoryBufferLen(len(" << arg << "))" << endl <<
+          indent() << "defer " << mbTrans << ".Close()" << endl <<
+          indent() << "_, " << err1 << " := " << mbTrans << ".WriteString(" << arg << ")" << endl <<
+          indent() << "if " << err1 << " != nil { " << endl <<
+          indent() << "  Usage()" << endl <<
+          indent() << "  return" << endl <<
+          indent() << "}" << endl <<
+          indent() << factory << " := thrift.NewTSimpleJSONProtocolFactory()" << endl <<
+          indent() << jsProt << " := " << factory << ".GetProtocol(" << mbTrans << ")" << endl <<
+          indent() << "containerStruct" << i << " := " << package_name_ << ".New" << pubName << "Args()" << endl <<
+          indent() << err2 << " := containerStruct" << i << ".ReadField" << (i + 1) << "(" << jsProt << ")" << endl <<
+          indent() << "if " << err2 << " != nil {" << endl <<
+          indent() << "  Usage()" << endl <<
+          indent() << "  return" << endl <<
+          indent() << "}" << endl <<
+          indent() << "argvalue" << i << " := containerStruct" << i << "." << argName << endl;
+      } else {
+        throw("Invalid argument type in generate_service_remote");
+        string err1(tmp("err"));
+        f_remote <<
+          indent() << "argvalue" << i << ", " << err1 << " := eval(flag.Arg(" << flagArg << "))" << endl <<
+          indent() << "if " << err1 << " != nil {" << endl <<
+          indent() << "  Usage()" << endl <<
+          indent() << "  return" << endl <<
+          indent() << "}" << endl;
+      }
+      if(the_type->is_typedef()) {
+        f_remote <<
+          indent() << "value" << i << " := " << package_name_ << "." << publicize(the_type->get_name()) << "(argvalue" << i << ")" << endl;
+      } else {
+        f_remote <<
+          indent() << "value" << i << " := argvalue" << i << endl;
+      }
+    }
+    f_remote <<
+      indent() << "fmt.Print(client." << pubName << "(";
+    bool argFirst = true;
+    for (int i = 0; i < num_args; ++i) {
+      if (argFirst) {
+        argFirst = false;
+      } else {
+        f_remote << ", ";
+      }
+      if(args[i]->get_type()->is_enum()) {
+        f_remote << "value" << i;
+      } else if(args[i]->get_type()->is_base_type()) {
+        t_base_type::t_base e = ((t_base_type*)(args[i]->get_type()))->get_base();
+        switch(e) {
+          case t_base_type::TYPE_VOID: break;
+          case t_base_type::TYPE_STRING:
+          case t_base_type::TYPE_BOOL:
+          case t_base_type::TYPE_BYTE:
+          case t_base_type::TYPE_I16:
+          case t_base_type::TYPE_I32:
+          case t_base_type::TYPE_I64:
+          case t_base_type::TYPE_DOUBLE:
+            f_remote << "value" << i;
+            break;
+          default:
+            throw("Invalid base type in generate_service_remote");
+        }
+        //f_remote << publicize(args[i]->get_name()) << "(strconv.Atoi(flag.Arg(" << flagArg << ")))";
+      } else {
+        f_remote << "value" << i;
+      }
+    }
+    f_remote <<
+      "))" << endl <<
+      indent() << "fmt.Print(\"\\n\")" << endl <<
+      indent() << "break" << endl;
+    indent_down();
+  }
+  f_remote <<
+    indent() << "case \"\":" << endl <<
+    indent() << "  Usage()" << endl <<
+    indent() << "  break" << endl <<
+    indent() << "default:" << endl <<
+    indent() << "  fmt.Fprint(os.Stderr, \"Invalid function \", cmd, \"\\n\")" << endl <<
+    indent() << "}" << endl;
+  indent_down();
+  
+  f_remote << 
+    indent() << "}" << endl;
+  
+
+  // Close service file
+  f_remote.close();
+
+  // Make file executable, love that bitwise OR action
+  chmod(f_remote_name.c_str(),
+          S_IRUSR
+        | S_IWUSR
+        | S_IXUSR
+#ifndef MINGW
+        | S_IRGRP
+        | S_IXGRP
+        | S_IROTH
+        | S_IXOTH
+#endif
+  );
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_go_generator::generate_service_server(t_service* tservice) {
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  string extends = "";
+  string extends_processor = "";
+  string extends_processor_new = "";
+  string serviceName(publicize(tservice->get_name()));
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    size_t index = extends.rfind(".");
+    if(index != string::npos) {
+      extends_processor = extends.substr(0, index + 1) + publicize(extends.substr(index + 1)) + "Processor";
+      extends_processor_new = extends.substr(0, index + 1) + "New" + publicize(extends.substr(index + 1)) + "Processor";
+    } else {
+      extends_processor = publicize(extends) + "Processor";
+      extends_processor_new = "New" + extends_processor;
+    }
+  }
+  string pServiceName(privatize(serviceName));
+
+  // Generate the header portion
+  string self(tmp("self"));
+  if(extends_processor.empty()) {
+    f_service_ <<
+      indent() << "type " << serviceName << "Processor struct {" << endl <<
+      indent() << "  handler I" << serviceName << endl <<
+      indent() << "  processorMap map[string]thrift.TProcessorFunction" << endl <<
+      indent() << "}" << endl << endl <<
+      indent() << "func (p *" << serviceName << "Processor) Handler() I" << serviceName << " {" << endl <<
+      indent() << "  return p.handler" << endl <<
+      indent() << "}" << endl << endl <<
+      indent() << "func (p *" << serviceName << "Processor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) {" << endl <<
+      indent() << "  p.processorMap[key] = processor" << endl <<
+      indent() << "}" << endl << endl <<
+      indent() << "func (p *" << serviceName << "Processor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, exists bool) {" << endl <<
+      indent() << "  processor, exists = p.processorMap[key]" << endl <<
+      indent() << "  return processor, exists" << endl <<
+      indent() << "}" << endl << endl <<
+      indent() << "func (p *" << serviceName << "Processor) ProcessorMap() map[string]thrift.TProcessorFunction {" << endl <<
+      indent() << "  return p.processorMap" << endl <<
+      indent() << "}" << endl << endl <<
+      indent() << "func New" << serviceName << "Processor(handler I" << serviceName << ") *" << serviceName << "Processor {" << endl << endl <<
+      indent() << "  " << self << " := &" << serviceName << "Processor{handler:handler, processorMap:make(map[string]thrift.TProcessorFunction)}" << endl;
+    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+      string escapedFuncName(escape_string((*f_iter)->get_name()));
+      f_service_ <<
+        indent() << "  " << self << ".processorMap[\"" << escapedFuncName << "\"] = &" << pServiceName << "Processor" << publicize((*f_iter)->get_name()) << "{handler:handler}" << endl;
+    }
+    string x(tmp("x"));
+    f_service_ <<
+      indent() << "return " << self << endl <<
+      indent() << "}" << endl << endl <<
+      indent() << "func (p *" << serviceName << "Processor) Process(iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {" << endl <<
+      indent() << "  name, _, seqId, err := iprot.ReadMessageBegin()" << endl <<
+      indent() << "  if err != nil { return }" << endl <<
+      indent() << "  process, nameFound := p.GetProcessorFunction(name)" << endl <<
+      indent() << "  if !nameFound || process == nil {" << endl <<
+      indent() << "    iprot.Skip(thrift.STRUCT)" << endl <<
+      indent() << "    iprot.ReadMessageEnd()" << endl <<
+      indent() << "    " << x << " := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, \"Unknown function \" + name)" << endl <<
+      indent() << "    oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId)" << endl <<
+      indent() << "    " << x << ".Write(oprot)" << endl <<
+      indent() << "    oprot.WriteMessageEnd()" << endl <<
+      indent() << "    oprot.Transport().Flush()" << endl <<
+      indent() << "    return false, " << x << endl <<
+      indent() << "  }" << endl <<
+      indent() << "  return process.Process(seqId, iprot, oprot)" << endl <<
+      indent() << "}" << endl << endl;
+  } else {
+    f_service_ <<
+      indent() << "type " << serviceName << "Processor struct {" << endl <<
+      indent() << "  super *" << extends_processor << endl <<
+      indent() << "}" << endl << endl <<
+      indent() << "func (p *" << serviceName << "Processor) Handler() I" << serviceName << " {" << endl <<
+      indent() << "  return p.super.Handler().(I" << serviceName << ")" << endl <<
+      indent() << "}" << endl << endl <<
+      indent() << "func (p *" << serviceName << "Processor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) {" << endl <<
+      indent() << "  p.super.AddToProcessorMap(key, processor)" << endl <<
+      indent() << "}" << endl << endl <<
+      indent() << "func (p *" << serviceName << "Processor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, exists bool) {" << endl <<
+      indent() << "  return p.super.GetProcessorFunction(key)" << endl <<
+      indent() << "}" << endl << endl <<
+      indent() << "func (p *" << serviceName << "Processor) ProcessorMap() map[string]thrift.TProcessorFunction {" << endl <<
+      indent() << "  return p.super.ProcessorMap()" << endl <<
+      indent() << "}" << endl << endl <<
+      indent() << "func New" << serviceName << "Processor(handler I" << serviceName << ") *" << serviceName << "Processor {" << endl <<
+      indent() << "  " << self << " := &" << serviceName << "Processor{super: " << extends_processor_new << "(handler)}" << endl;
+    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+      string escapedFuncName(escape_string((*f_iter)->get_name()));
+      f_service_ <<
+        indent() << "  " << self << ".AddToProcessorMap(\"" << escapedFuncName << "\", &" << pServiceName << "Processor" << publicize((*f_iter)->get_name()) << "{handler:handler})" << endl;
+    }
+    f_service_ <<
+      indent() << "  return " << self << endl <<
+      indent() << "}" << endl << endl <<
+      indent() << "func (p *" << serviceName << "Processor) Process(iprot, oprot thrift.TProtocol) (bool, thrift.TException) {" << endl <<
+      indent() << "  return p.super.Process(iprot, oprot)" << endl <<
+      indent() << "}" << endl << endl;
+  }
+  
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
+
+  f_service_ << endl;
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_go_generator::generate_process_function(t_service* tservice,
+                                               t_function* tfunction) {
+  // Open function
+  string processorName = privatize(tservice->get_name()) + "Processor" + publicize(tfunction->get_name());
+  
+  string argsname = publicize(tfunction->get_name()) + "Args";
+  string resultname = publicize(tfunction->get_name()) + "Result";
+  
+  //t_struct* xs = tfunction->get_xceptions();
+  //const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+  
+  f_service_ <<
+    indent() << "type " << processorName << " struct {" << endl <<
+    indent() << "  handler I" << publicize(tservice->get_name()) << endl <<
+    indent() << "}" << endl << endl <<
+    indent() << "func (p *" << processorName << ") Process(seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {" << endl;
+  indent_up();
+  
+  f_service_ <<
+    indent() << "args := New" << argsname << "()" << endl <<
+    indent() << "if err = args.Read(iprot); err != nil {" << endl <<
+    indent() << "  iprot.ReadMessageEnd()" << endl <<
+    indent() << "  x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.String())" << endl <<
+    indent() << "  oprot.WriteMessageBegin(\"" << escape_string(tfunction->get_name()) << "\", thrift.EXCEPTION, seqId)" << endl <<
+    indent() << "  x.Write(oprot)" << endl <<
+    indent() << "  oprot.WriteMessageEnd()" << endl <<
+    indent() << "  oprot.Transport().Flush()" << endl <<
+    indent() << "  return" << endl <<
+    indent() << "}" << endl <<
+    indent() << "iprot.ReadMessageEnd()" << endl <<
+    indent() << "result := New" << resultname << "()" << endl <<
+    indent() << "if ";
+  if (!tfunction->is_oneway()) {
+    if(!tfunction->get_returntype()->is_void()) {
+      f_service_ << "result.Success, ";
+    }
+    t_struct* exceptions = tfunction->get_xceptions();
+    const vector<t_field*>& fields = exceptions->get_members();
+    vector<t_field*>::const_iterator f_iter;
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      f_service_ << "result." << publicize((*f_iter)->get_name()) << ", ";
+    }
+  }
+  
+  
+  // Generate the function call
+  t_struct* arg_struct = tfunction->get_arglist();
+  const std::vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  f_service_ <<
+    "err = p.handler." << publicize(tfunction->get_name()) << "(";
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f_service_ << ", ";
+    }
+    f_service_ << "args." << publicize((*f_iter)->get_name());
+  }
+  f_service_ << "); err != nil {" << endl <<
+    indent() << "  x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, \"Internal error processing " << escape_string(tfunction->get_name()) << ": \" + err.String())" << endl <<
+    indent() << "  oprot.WriteMessageBegin(\"" << escape_string(tfunction->get_name()) << "\", thrift.EXCEPTION, seqId)" << endl <<
+    indent() << "  x.Write(oprot)" << endl <<
+    indent() << "  oprot.WriteMessageEnd()" << endl <<
+    indent() << "  oprot.Transport().Flush()" << endl <<
+    indent() << "  return" << endl <<
+    indent() << "}" << endl <<
+    indent() << "if err2 := oprot.WriteMessageBegin(\"" << escape_string(tfunction->get_name()) << "\", thrift.REPLY, seqId); err2 != nil {" << endl <<
+    indent() << "  err = err2" << endl <<
+    indent() << "}" << endl <<
+    indent() << "if err2 := result.Write(oprot); err == nil && err2 != nil {" << endl <<
+    indent() << "  err = err2" << endl <<
+    indent() << "}" << endl <<
+    indent() << "if err2 := oprot.WriteMessageEnd(); err == nil && err2 != nil {" << endl <<
+    indent() << "  err = err2" << endl <<
+    indent() << "}" << endl <<
+    indent() << "if err2 := oprot.Transport().Flush(); err == nil && err2 != nil {" << endl <<
+    indent() << "  err = err2" << endl <<
+    indent() << "}" << endl <<
+    indent() << "if err != nil {" << endl <<
+    indent() << "  return" << endl <<
+    indent() << "}" << endl <<
+    indent() << "return true, err" << endl;
+  indent_down();
+  f_service_ <<
+    indent() << "}" << endl << endl;
+  /*
+  indent(f_service_) <<
+      "func (p *" << publicize(tservice->get_name()) << "Client) WriteResultsSuccess" << publicize(tfunction->get_name()) <<
+      "(success bool, result " << publicize(tfunction->get_name()) << "Result, seqid int32, oprot thrift.TProtocol) (err os.Error) {" << endl;
+  indent_up();
+  f_service_ <<
+    indent() << "result.Success = success" << endl <<
+    indent() << "oprot.WriteMessageBegin(\"" << escape_string(tfunction->get_name()) << "\", thrift.REPLY, seqid)" << endl <<
+    indent() << "result.Write(oprot)" << endl <<
+    indent() << "oprot.WriteMessageEnd()" << endl <<
+    indent() << "oprot.Transport().Flush()" << endl <<
+    indent() << "return" << endl;
+  indent_down();
+  f_service_ << 
+    indent() << "}" << endl << endl;
+  */
+  // Try block for a function with exceptions
+  /*
+  if (!tfunction->is_oneway() && xceptions.size() > 0) {
+    indent(f_service_) <<
+      "func (p *" << publicize(tservice->get_name()) << "Client) WriteResultsException" << publicize(tfunction->get_name()) <<
+      "(error *" << publicize(tfunction->get_name()) << ", result *, seqid, oprot) (err os.Error) {" << endl;
+    indent_up();
+
+    // Kinda absurd
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      f_service_ <<
+        indent() << "except " << type_name((*x_iter)->get_type()) << ", " << (*x_iter)->get_name() << ":" << endl;
+      if (!tfunction->is_oneway()) {
+        indent_up();
+        f_service_ <<
+          indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << endl;
+        indent_down();
+      } else {
+        f_service_ <<
+          indent() << "pass" << endl;
+      }
+    }
+    f_service_ <<
+      indent() << "err = oprot.WriteMessageBegin(\"" << escape_string(tfunction->get_name()) << "\", thrift.REPLY, seqid)" << endl <<
+      indent() << "if err != nil { return err }" << endl <<
+      indent() << "err = result.Write(oprot)" << endl <<
+      indent() << "if err != nil { return err }" << endl <<
+      indent() << "err = oprot.WriteMessageEnd()" << endl <<
+      indent() << "if err != nil { return err }" << endl <<
+      indent() << "err = oprot.Transport().Flush()" << endl <<
+      indent() << "if err != nil { return err }" << endl;
+    indent_down();
+    f_service_ << "}" << endl << endl;
+  }
+  */
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_go_generator::generate_deserialize_field(ofstream &out,
+                                                t_field* tfield,
+                                                bool declare,
+                                                string prefix,
+                                                string err,
+                                                bool inclass,
+                                                bool coerceData) {
+  t_type* orig_type = tfield->get_type();
+  t_type* type = get_true_type(orig_type);
+  string name(prefix + publicize(tfield->get_name()));
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + name;
+  }
+  string v = tmp("v");
+  string err2 = tmp("err");
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out,
+                                (t_struct*)type,
+                                declare,
+                                name,
+                                err);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, declare, name, err);
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent(out) <<
+      v << ", " << err2 << " := iprot.";
+
+    if (type->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw "compiler error: cannot serialize void field in a struct: " +
+          name;
+        break;
+      case t_base_type::TYPE_STRING:
+        out << "ReadString()";
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "ReadBool()";
+        break;
+      case t_base_type::TYPE_BYTE:
+        out << "ReadByte()";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "ReadI16()";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "ReadI32()";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "ReadI64()";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "ReadDouble()";
+        break;
+      default:
+        throw "compiler error: no Go name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "ReadI32()";
+    }
+    string structName("\"\"");
+    if(!prefix.size() || prefix.find(".") == string::npos) {
+      structName = "\"\"";
+    } else {
+      structName = prefix + "ThriftName()";
+    }
+    out << endl <<
+      indent() << "if " << err2 << " != nil { return thrift.NewTProtocolExceptionReadField(" <<
+                           tfield->get_key()  <<
+                           ", \"" << escape_string(tfield->get_name()) <<
+                           "\", " << structName << ", " << err2 << "); }" << endl;
+    if(!prefix.size() || prefix.find(".") == string::npos) {
+      if(type->is_enum() || orig_type->is_typedef()) {
+        indent(out) << name << " := " << publicize(orig_type->get_name()) << "("<< v << ")" << endl;
+      } else {
+        indent(out) << name << " := " << v << endl;
+      }
+    } else {
+      if(type->is_enum() || orig_type->is_typedef()) {
+        indent(out) << name << " = " << publicize(orig_type->get_name()) << "("<< v << ")" << endl;
+      } else {
+        indent(out) << name << " = " << v << endl;
+      }
+    }
+
+  } else {
+    throw "INVALID TYPE IN generate_deserialize_field '" + type->get_name() + "' for field '" + tfield->get_name() + "'";
+  }
+}
+
+/**
+ * Generates an unserializer for a struct, calling read()
+ */
+void t_go_generator::generate_deserialize_struct(ofstream &out,
+                                                  t_struct* tstruct,
+                                                  bool declare,
+                                                  string prefix,
+                                                  string err) {
+  string err2(tmp("err"));
+  string eq(" := ");
+  if(!declare) {
+    eq = " = ";
+  }
+  out <<
+    indent() << prefix << eq << "New" << publicize(type_name(tstruct)) << "()" << endl <<
+    indent() << err2 << " := " << prefix << ".Read(iprot)" << endl <<
+    indent() << "if " << err2 << " != nil { return thrift.NewTProtocolExceptionReadStruct(\"" <<
+                         escape_string(prefix + tstruct->get_name()) << "\", " <<
+                         err2 << "); }\n";
+}
+
+/**
+ * Serialize a container by writing out the header followed by
+ * data and then a footer.
+ */
+void t_go_generator::generate_deserialize_container(ofstream &out,
+                                                    t_type* ttype,
+                                                    bool   declare,
+                                                    string prefix,
+                                                    string err) {
+  string size = tmp("_size");
+  string ktype = tmp("_ktype");
+  string vtype = tmp("_vtype");
+  string etype = tmp("_etype");
+
+  t_field fsize(g_type_i32, size);
+  t_field fktype(g_type_byte, ktype);
+  t_field fvtype(g_type_byte, vtype);
+  t_field fetype(g_type_byte, etype);
+  
+  string eq(" = ");
+  if(declare)
+    eq = " := ";
+
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    out <<
+      indent() << ktype << ", " << vtype << ", " << size << ", " << err << " := iprot.ReadMapBegin()" << endl <<
+      indent() << "if " << err << " != nil {" << endl <<
+      indent() << "  return thrift.NewTProtocolExceptionReadField(" <<
+                           -1 << ", \"" <<
+                           escape_string(prefix) << "\", \"\", " << 
+                           err << ")" << endl <<
+      indent() << "}" << endl <<
+      indent() << prefix << eq << "thrift.NewTMap(" << ktype << ", " << vtype << ", " << size << ")" << endl;
+  } else if (ttype->is_set()) {
+    out <<
+      indent() << etype << ", " << size << ", " << err << " := iprot.ReadSetBegin()" << endl <<
+      indent() << "if " << err << " != nil {" << endl <<
+      indent() <<"  return thrift.NewTProtocolExceptionReadField(" <<
+                           -1 << ", \"" <<
+                           escape_string(prefix) << "\", \"\", " << 
+                           err << "); }" << endl <<
+      indent() << "}" << endl <<
+      indent() << prefix << eq << "thrift.NewTSet(" << etype << ", " << size << ")" << endl;
+  } else if (ttype->is_list()) {
+    out <<
+      indent() << etype << ", " << size << ", " << err << " := iprot.ReadListBegin()" << endl <<
+      indent() << "if " << err << " != nil {" << endl <<
+      indent() <<"  return thrift.NewTProtocolExceptionReadField(" <<
+                           -1 << ", \"" <<
+                           escape_string(prefix) << "\", \"\", " << 
+                           err << ")" << endl <<
+      indent() << "}" << endl <<
+      indent() << prefix << eq << "thrift.NewTList(" << etype << ", " << size << ")" << endl;
+  } else {
+    throw "INVALID TYPE IN generate_deserialize_container '" + ttype->get_name() + "' for prefix '" + prefix + "'";
+  }
+
+  // For loop iterates over elements
+  string i = tmp("_i");
+  out <<
+    indent() << "for " << i << ":= 0; " << i << " < " << size << "; " << i << "++ {" << endl;
+  indent_up();
+
+  if (ttype->is_map()) {
+    generate_deserialize_map_element(out, (t_map*)ttype, declare, prefix);
+  } else if (ttype->is_set()) {
+    generate_deserialize_set_element(out, (t_set*)ttype, declare, prefix);
+  } else if (ttype->is_list()) {
+    generate_deserialize_list_element(out, (t_list*)ttype, declare, prefix);
+  }
+
+  indent_down();
+  out <<
+    indent() << "}" << endl;
+  // Read container end
+  if (ttype->is_map()) {
+    out <<
+      indent() << err << " = iprot.ReadMapEnd()" << endl <<
+      indent() << "if " << err << " != nil { return thrift.NewTProtocolExceptionReadField(" 
+                        << -1
+                        << ", \"" << escape_string(((t_map*)ttype)->get_cpp_name())
+                        << "\", " << "\"map\", " << err << "); }" << endl;
+  } else if (ttype->is_set()) {
+    out <<
+      indent() << err << " = iprot.ReadSetEnd()" << endl <<
+      indent() << "if " << err << " != nil { return thrift.NewTProtocolExceptionReadField(" 
+                        << -1
+                        << ", \"" << escape_string(((t_set*)ttype)->get_cpp_name())
+                        << "\", " << "\"set\", " << err << "); }" << endl;
+  } else if (ttype->is_list()) {
+    out <<
+      indent() << err << " = iprot.ReadListEnd()" << endl <<
+      indent() << "if " << err << " != nil { return thrift.NewTProtocolExceptionReadField(" 
+                        << -1
+                        << ", \"" << escape_string(((t_list*)ttype)->get_cpp_name())
+                        << "\", " << "\"list\"," << err << "); }" << endl;
+  }
+}
+
+
+/**
+ * Generates code to deserialize a map
+ */
+void t_go_generator::generate_deserialize_map_element(ofstream &out,
+                                                       t_map* tmap,
+                                                       bool   declare,
+                                                       string prefix,
+                                                       string err) {
+  string key = tmp("_key");
+  string val = tmp("_val");
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+
+  generate_deserialize_field(out, &fkey, true);
+  generate_deserialize_field(out, &fval, true);
+
+  indent(out) <<
+    prefix << ".Set(" << key << ", " << val << ")" << endl;
+}
+
+/**
+ * Write a set element
+ */
+void t_go_generator::generate_deserialize_set_element(ofstream &out,
+                                                       t_set* tset,
+                                                       bool   declare,
+                                                       string prefix,
+                                                       string err) {
+  string elem = tmp("_elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  generate_deserialize_field(out, &felem, true, "", err);
+
+  indent(out) <<
+    prefix << ".Add(" << elem << ")" << endl;
+}
+
+/**
+ * Write a list element
+ */
+void t_go_generator::generate_deserialize_list_element(ofstream &out,
+                                                        t_list* tlist,
+                                                        bool   declare,
+                                                        string prefix,
+                                                        string err) {
+  string elem = tmp("_elem");
+  t_field felem(tlist->get_elem_type(), elem);
+
+  generate_deserialize_field(out, &felem, true, "", err);
+
+  indent(out) <<
+    prefix << ".Push(" << elem << ")" << endl;
+}
+
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_go_generator::generate_serialize_field(ofstream &out,
+                                               t_field* tfield,
+                                               string prefix,
+                                               string err) {
+  t_type* type = get_true_type(tfield->get_type());
+  string name(prefix + publicize(tfield->get_name()));
+
+  // Do nothing for void types
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name;
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out,
+                              (t_struct*)type,
+                              name,
+                              err);
+  } else if (type->is_container()) {
+    generate_serialize_container(out,
+                                 type,
+                                 name,
+                                 err);
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    indent(out) <<
+      err << " = oprot.";
+
+    if (type->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw
+          "compiler error: cannot serialize void field in a struct: " + name;
+        break;
+      case t_base_type::TYPE_STRING:
+        out << "WriteString(string(" << name << "))";
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "WriteBool(bool(" << name << "))";
+        break;
+      case t_base_type::TYPE_BYTE:
+        out << "WriteByte(byte(" << name << "))";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "WriteI16(int16(" << name << "))";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "WriteI32(int32(" << name << "))";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "WriteI64(int64(" << name << "))";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "WriteDouble(float64(" << name << "))";
+        break;
+      default:
+        throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "WriteI32(int32(" << name << "))";
+    }
+    string structName = (prefix.size()) ? prefix + "ThriftName()" : "\"\"";
+    out << endl <<
+      indent() << "if " << err << " != nil { return thrift.NewTProtocolExceptionWriteField(" 
+                        << tfield->get_key()
+                        << ", \"" << escape_string(tfield->get_name())
+                        << "\", " << structName << ", " << err << "); }\n";
+  } else {
+    throw "INVALID TYPE IN generate_serialize_field '" + type->get_name() + "' for field '" + prefix + publicize(tfield->get_name()) + "'";
+  }
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix  String prefix to attach to all fields
+ */
+void t_go_generator::generate_serialize_struct(ofstream &out,
+                                               t_struct* tstruct,
+                                               string prefix,
+                                               string err) {
+  out <<
+    indent() << err << " = " << prefix << ".Write(oprot)" << endl <<
+    indent() << "if " << err << " != nil { return thrift.NewTProtocolExceptionWriteStruct(" 
+                      << "\"" << escape_string(tstruct->get_name()) << "\", " << err << "); }\n";
+}
+
+void t_go_generator::generate_serialize_container(ofstream &out,
+                                                  t_type* ttype,
+                                                  string prefix,
+                                                  string err) {
+  if (ttype->is_map()) {
+    out <<
+      indent() << err << " = oprot.WriteMapBegin(" <<
+                         type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
+                         type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
+                         prefix << ".Len())" << endl <<
+      indent() << "if " << err << " != nil { return thrift.NewTProtocolExceptionWriteField(" 
+                        << -1
+                        << ", \"" << escape_string(ttype->get_name())
+                        << "\", " << "\"map\", " << err << "); }\n";
+  } else if (ttype->is_set()) {
+    out <<
+      indent() << err << " = oprot.WriteSetBegin(" <<
+                         type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
+                         prefix << ".Len())" << endl <<
+      indent() << "if " << err << " != nil { return thrift.NewTProtocolExceptionWriteField(" 
+                        << -1
+                        << ", \"" << escape_string(ttype->get_name())
+                        << "\", " << "\"set\", " << err << "); }\n";
+  } else if (ttype->is_list()) {
+    out <<
+      indent() << err << " = oprot.WriteListBegin(" <<
+                         type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
+                         prefix << ".Len())" << endl <<
+      indent() << "if " << err << " != nil { return thrift.NewTProtocolExceptionWriteField(" 
+                        << -1
+                        << ", \"" << escape_string(ttype->get_name())
+                        << "\", " << "\"list\", " << err << "); }\n";
+  } else {
+    throw "INVALID TYPE IN generate_serialize_container '" + ttype->get_name() + "' for prefix '" + prefix + "'";
+  }
+
+  if (ttype->is_map()) {
+    string miter = tmp("Miter");
+    string kiter = tmp("Kiter");
+    string viter = tmp("Viter");
+    t_map* tmap = (t_map*)ttype;
+    out <<
+      indent() << "for " << miter << " := range " << prefix << ".Iter() {" << endl <<
+      indent() << "  " << kiter << ", " << viter << " := " << miter << ".Key().(" << type_to_go_type(tmap->get_key_type()) << "), " << miter << ".Value().(" << type_to_go_type(tmap->get_val_type()) << ")" << endl;
+    indent_up();
+    generate_serialize_map_element(out, tmap, kiter, viter);
+    indent_down();
+    indent(out) << "}" << endl;
+  } else if (ttype->is_set()) {
+    t_set* tset = (t_set*)ttype;
+    string iter = tmp("Iter");
+    string iter2 = tmp("Iter");
+    out <<
+      indent() << "for " << iter << " := " << prefix << ".Front(); " << iter << " != nil; " << iter << " = " << iter << ".Next() {" << endl <<
+      indent() << "  " << iter2 << " := " << iter << ".Value.(" << type_to_go_type(tset->get_elem_type()) << ")" << endl;
+    indent_up();
+    generate_serialize_set_element(out, tset, iter2);
+    indent_down();
+    indent(out) << "}" << endl;
+  } else if (ttype->is_list()) {
+    t_list* tlist = (t_list*)ttype;
+    string iter = tmp("Iter");
+    string iter2 = tmp("Iter");
+    out <<
+      indent() << "for " << iter << " := range " << prefix << ".Iter() {" << endl <<
+      indent() << "  " << iter2 << " := " << iter << ".(" << type_to_go_type(tlist->get_elem_type()) << ")" << endl;
+    indent_up();
+    generate_serialize_list_element(out, tlist, iter2);
+    indent_down();
+    indent(out) << "}" << endl;
+  }
+
+  if (ttype->is_map()) {
+    out <<
+      indent() << err << " = oprot.WriteMapEnd()" << endl <<
+      indent() << "if " << err << " != nil { return thrift.NewTProtocolExceptionWriteField(" 
+                        << -1
+                        << ", \"" << escape_string(ttype->get_name())
+                        << "\", " << "\"map\", " << err << "); }\n";
+  } else if (ttype->is_set()) {
+    out <<
+      indent() << err << " = oprot.WriteSetEnd()" << endl <<
+      indent() << "if " << err << " != nil { return thrift.NewTProtocolExceptionWriteField(" 
+                        << -1
+                        << ", \"" << escape_string(ttype->get_name())
+                        << "\", " << "\"set\", " << err << "); }\n";
+  } else if (ttype->is_list()) {
+    out <<
+      indent() << err << " = oprot.WriteListEnd()" << endl <<
+      indent() << "if " << err << " != nil { return thrift.NewTProtocolExceptionWriteField(" 
+                        << -1
+                        << ", \"" << escape_string(ttype->get_name())
+                        << "\", " << "\"list\", " << err << "); }\n";
+  }
+}
+
+/**
+ * Serializes the members of a map.
+ *
+ */
+void t_go_generator::generate_serialize_map_element(ofstream &out,
+                                                     t_map* tmap,
+                                                     string kiter,
+                                                     string viter,
+                                                     string err) {
+  t_field kfield(tmap->get_key_type(), kiter);
+  generate_serialize_field(out, &kfield, "", err);
+
+  t_field vfield(tmap->get_val_type(), viter);
+  generate_serialize_field(out, &vfield, "", err);
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_go_generator::generate_serialize_set_element(ofstream &out,
+                                                     t_set* tset,
+                                                     string iter,
+                                                     string err) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "", err);
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_go_generator::generate_serialize_list_element(ofstream &out,
+                                                      t_list* tlist,
+                                                      string iter,
+                                                      string err) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "", err);
+}
+
+/**
+ * Generates the docstring for a given struct.
+ */
+void t_go_generator::generate_go_docstring(ofstream& out,
+                                               t_struct* tstruct) {
+  generate_go_docstring(out, tstruct, tstruct, "Attributes");
+}
+
+/**
+ * Generates the docstring for a given function.
+ */
+void t_go_generator::generate_go_docstring(ofstream& out,
+                                               t_function* tfunction) {
+  generate_go_docstring(out, tfunction, tfunction->get_arglist(), "Parameters");
+}
+
+/**
+ * Generates the docstring for a struct or function.
+ */
+void t_go_generator::generate_go_docstring(ofstream& out,
+                                               t_doc*    tdoc,
+                                               t_struct* tstruct,
+                                               const char* subheader) {
+  bool has_doc = false;
+  stringstream ss;
+  if (tdoc->has_doc()) {
+    has_doc = true;
+    ss << tdoc->get_doc();
+  }
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  if (fields.size() > 0) {
+    if (has_doc) {
+      ss << endl;
+    }
+    has_doc = true;
+    ss << subheader << ":\n";
+    vector<t_field*>::const_iterator p_iter;
+    for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
+      t_field* p = *p_iter;
+      ss << " - " << publicize(p->get_name());
+      if (p->has_doc()) {
+        ss << ": " << p->get_doc();
+      } else {
+        ss << endl;
+      }
+    }
+  }
+
+  if (has_doc) {
+    generate_docstring_comment(out,
+      "/**\n",
+      " * ", ss.str(),
+      " */\n");
+  }
+}
+
+/**
+ * Generates the docstring for a generic object.
+ */
+void t_go_generator::generate_go_docstring(ofstream& out,
+                                               t_doc* tdoc) {
+  if (tdoc->has_doc()) {
+    generate_docstring_comment(out,
+      "/**\n",
+      " *", tdoc->get_doc(),
+      " */\n");
+  }
+}
+
+/**
+ * Declares an argument, which may include initialization as necessary.
+ *
+ * @param tfield The field
+ */
+string t_go_generator::declare_argument(t_field* tfield) {
+  std::ostringstream result;
+  result << publicize(tfield->get_name()) << "=";
+  if (tfield->get_value() != NULL) {
+    result << "thrift_spec[" <<
+      tfield->get_key() << "][4]";
+  } else {
+    result << "nil";
+  }
+  return result.str();
+}
+
+/**
+ * Renders a field default value, returns nil otherwise.
+ *
+ * @param tfield The field
+ */
+string t_go_generator::render_field_default_value(t_field* tfield, const string& name) {
+  t_type* type = get_true_type(tfield->get_type());
+  if (tfield->get_value() != NULL) {
+    return render_const_value(type, tfield->get_value(), name);
+  } else {
+    return "nil";
+  }
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_go_generator::function_signature(t_function* tfunction,
+                                          string prefix) {
+  // TODO(mcslee): Nitpicky, no ',' if argument_list is empty
+  return
+    publicize(prefix + tfunction->get_name()) + 
+      "(" + argument_list(tfunction->get_arglist()) + ")";
+}
+
+/**
+ * Renders an interface function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_go_generator::function_signature_if(t_function* tfunction,
+                                             string prefix,
+                                             bool addOsError) {
+  // TODO(mcslee): Nitpicky, no ',' if argument_list is empty
+  string signature = publicize(prefix + tfunction->get_name()) + "(";
+  signature += argument_list(tfunction->get_arglist()) + ") (";
+  t_type* ret = tfunction->get_returntype();
+  t_struct* exceptions = tfunction->get_xceptions();
+  string errs = argument_list(exceptions);
+  string retval(tmp("retval"));
+  if(!ret->is_void()) {
+    signature += retval + " " + type_to_go_type(ret);
+    if(addOsError || errs.size()==0) {
+      signature += ", ";
+    }
+  }
+  if(errs.size()>0) {
+    signature += errs;
+    if(addOsError)
+      signature += ", ";
+  }
+  if(addOsError) {
+    signature += "err os.Error";
+  }
+  signature += ")";
+  return signature;
+}
+
+
+/**
+ * Renders a field list
+ */
+string t_go_generator::argument_list(t_struct* tstruct) {
+  string result = "";
+  
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      result += ", ";
+    }
+    result += (*f_iter)->get_name() + " " + type_to_go_type((*f_iter)->get_type());
+  }
+  return result;
+}
+
+string t_go_generator::type_name(t_type* ttype) {
+  t_program* program = ttype->get_program();
+  if (ttype->is_service()) {
+    return get_real_go_module(program) + "." + ttype->get_name();
+  }
+  if (program != NULL && program != program_) {
+    return get_real_go_module(program) + ".ttypes." + ttype->get_name();
+  }
+  return ttype->get_name();
+}
+
+/**
+ * Converts the parse type to a go tyoe
+ */
+string t_go_generator::type_to_enum(t_type* type) {
+  type = get_true_type(type);
+
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      throw "NO T_VOID CONSTRUCT";
+    case t_base_type::TYPE_STRING:
+      return "thrift.STRING";
+    case t_base_type::TYPE_BOOL:
+      return "thrift.BOOL";
+    case t_base_type::TYPE_BYTE:
+      return "thrift.BYTE";
+    case t_base_type::TYPE_I16:
+      return "thrift.I16";
+    case t_base_type::TYPE_I32:
+      return "thrift.I32";
+    case t_base_type::TYPE_I64:
+      return "thrift.I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "thrift.DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "thrift.I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "thrift.STRUCT";
+  } else if (type->is_map()) {
+    return "thrift.MAP";
+  } else if (type->is_set()) {
+    return "thrift.SET";
+  } else if (type->is_list()) {
+    return "thrift.LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+/**
+ * Converts the parse type to a go tyoe
+ */
+string t_go_generator::type_to_go_type(t_type* type) {
+  //type = get_true_type(type);
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      throw "";
+    case t_base_type::TYPE_STRING:
+      return "string";
+    case t_base_type::TYPE_BOOL:
+      return "bool";
+    case t_base_type::TYPE_BYTE:
+      return "byte";
+    case t_base_type::TYPE_I16:
+      return "int16";
+    case t_base_type::TYPE_I32:
+      return "int32";
+    case t_base_type::TYPE_I64:
+      return "int64";
+    case t_base_type::TYPE_DOUBLE:
+      return "float64";
+    }
+  } else if (type->is_enum()) {
+    return publicize(type->get_name());
+  } else if (type->is_struct() || type->is_xception()) {
+    return string("*") + publicize(type->get_name());
+  } else if (type->is_map()) {
+    return "thrift.TMap";
+    //t_map* t = (t_map*)type;
+    //string keyType = type_to_go_type(t->get_key_type());
+    //string valueType = type_to_go_type(t->get_val_type());
+    //return string("map[") + keyType + "]" + valueType;
+  } else if (type->is_set()) {
+    return "thrift.TSet";
+    //t_set* t = (t_set*)type;
+    //string elemType = type_to_go_type(t->get_elem_type());
+    //return string("[]") + elemType;
+  } else if (type->is_list()) {
+    return "thrift.TList";
+    //t_list* t = (t_list*)type;
+    //string elemType = type_to_go_type(t->get_elem_type());
+    //return string("[]") + elemType;
+  } else if (type->is_typedef()) {
+    return publicize(((t_typedef*)type)->get_symbolic());
+  }
+
+  throw "INVALID TYPE IN type_to_go_type: " + type->get_name();
+}
+
+
+/**
+ * Converts the parse type to a go tyoe
+ */
+bool t_go_generator::can_be_nil(t_type* type) {
+  type = get_true_type(type);
+
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      throw "Invalid Type for can_be_nil";
+    case t_base_type::TYPE_STRING:
+    case t_base_type::TYPE_BOOL:
+    case t_base_type::TYPE_BYTE:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+    case t_base_type::TYPE_DOUBLE:
+      return false;
+    }
+  } else if (type->is_enum()) {
+    return false;
+  } else if (type->is_struct() || type->is_xception()) {
+    return true;
+  } else if (type->is_map()) {
+    return true;
+  } else if (type->is_set()) {
+    return true;
+  } else if (type->is_list()) {
+    return true;
+  }
+
+  throw "INVALID TYPE IN can_be_nil: " + type->get_name();
+}
+
+
+
+/** See the comment inside generate_go_struct_definition for what this is. */
+string t_go_generator::type_to_spec_args(t_type* ttype) {
+  while (ttype->is_typedef()) {
+    ttype = ((t_typedef*)ttype)->get_type();
+  }
+
+  if (ttype->is_base_type() || ttype->is_enum()) {
+    return "nil";
+  } else if (ttype->is_struct() || ttype->is_xception()) {
+    return "(" + type_name(ttype) + ", " + type_name(ttype) + ".thrift_spec)";
+  } else if (ttype->is_map()) {
+    return "(" +
+      type_to_enum(((t_map*)ttype)->get_key_type()) + "," +
+      type_to_spec_args(((t_map*)ttype)->get_key_type()) + "," +
+      type_to_enum(((t_map*)ttype)->get_val_type()) + "," +
+      type_to_spec_args(((t_map*)ttype)->get_val_type()) +
+      ")";
+
+  } else if (ttype->is_set()) {
+    return "(" +
+      type_to_enum(((t_set*)ttype)->get_elem_type()) + "," +
+      type_to_spec_args(((t_set*)ttype)->get_elem_type()) +
+      ")";
+
+  } else if (ttype->is_list()) {
+    return "(" +
+      type_to_enum(((t_list*)ttype)->get_elem_type()) + "," +
+      type_to_spec_args(((t_list*)ttype)->get_elem_type()) +
+      ")";
+  }
+
+  throw "INVALID TYPE IN type_to_spec_args: " + ttype->get_name();
+}
+
+
+THRIFT_REGISTER_GENERATOR(go, "Go", "");
diff --git a/configure.ac b/configure.ac
index d5071b0..8cad0a1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -34,7 +34,7 @@
 
 AC_ARG_VAR([JAVA_PREFIX], [Prefix for installing the Java lib jar.
                            (Normal --prefix is ignored for Java because
-                           Java has different conevntions.)
+                           Java has different conventions.)
                            Default = "/usr/local/lib"])
 AS_IF([test "x$JAVA_PREFIX" = x], [JAVA_PREFIX="/usr/local/lib"])
 
@@ -68,6 +68,20 @@
 
 AC_SUBST(CABAL_CONFIGURE_FLAGS)
 
+AC_ARG_VAR([GOROOT], [Prefix for the Go source directory.
+                           (Normal --prefix is ignored for Go because
+                           Go has different conventions.)
+                           Default = "/usr/local/share/go"])
+AS_IF([test "x$GOROOT" = x], [GOROOT="/usr/local/share/go"])
+
+AC_ARG_VAR([GOARCH], [Architecture default for Go.
+                           Default = "amd64"])
+AS_IF([test "x$GOARCH" = x], [GOARCH="amd64"])
+
+AC_ARG_VAR([GOBIN], [Binary directory for Go.
+                           Default = "/usr/local/bin"])
+AS_IF([test "x$GOBIN" = x], [GOBIN="/usr/local/bin"])
+
 AC_PROG_CC
 AC_PROG_CPP
 AC_PROG_CXX
@@ -79,6 +93,8 @@
 AM_PROG_LEX
 AC_PROG_LN_S
 AC_PROG_MKDIR_P
+AC_PROG_AWK
+AC_PROG_RANLIB
 
 AC_LANG([C++])
 
@@ -231,6 +247,36 @@
 AC_SUBST(RUNHASKELL)
 AM_CONDITIONAL(WITH_HASKELL, [test "$have_haskell" = "yes"])
 
+AX_THRIFT_LIB(go, [Go], yes)
+if test "$with_go" = "yes";  then
+  case X"$GOARCH" in
+  Xamd64)
+    GOARCH_NUM=6
+  	;;
+  X386)
+    GOARCH_NUM=8
+  	;;
+  Xarm)
+    GOARCH_NUM=5
+  	;;
+  *)
+    GOARCH_NUM=6
+    ;;
+  esac
+  GO_C=${GOBIN}/${GOARCH_NUM}g
+  GO_L=${GOBIN}/${GOARCH_NUM}l
+  GOMAKE=${GOBIN}/gomake
+  GOINSTALL=${GOBIN}/goinstall
+  AC_PATH_PROG([GO_C], [${GOARCH_NUM}g])
+  AC_PATH_PROG([GO_L], [${GOARCH_NUM}l])
+  AC_PATH_PROG([GOMAKE], [gomake])
+  AC_PATH_PROG([GOINSTALL], [goinstall])
+  if [[ -x "$GO_C" -a -x "$GO_L" -a -x "$GOMAKE" -a -x "$GOINSTALL" ]] ; then
+    have_go="yes"
+  fi
+fi
+AM_CONDITIONAL(WITH_GO, [test "$have_go" = "yes"])
+
 AC_C_CONST
 AC_C_INLINE
 AC_C_VOLATILE
@@ -238,6 +284,8 @@
 AC_HEADER_STDBOOL
 AC_HEADER_STDC
 AC_HEADER_TIME
+AC_HEADER_SYS_WAIT
+AC_TYPE_SIGNAL
 AC_CHECK_HEADERS([arpa/inet.h])
 AC_CHECK_HEADERS([sys/param.h])
 AC_CHECK_HEADERS([fcntl.h])
@@ -370,6 +418,8 @@
 AM_CONDITIONAL([THRIFT_GEN_js], [test "$ax_thrift_gen_js" = "yes"])
 AX_THRIFT_GEN(javame, [JavaME], yes)
 AM_CONDITIONAL([THRIFT_GEN_javame], [test "$ax_thrift_gen_javame" = "yes"])
+AX_THRIFT_GEN(go, [GO_C], yes)
+AM_CONDITIONAL([THRIFT_GEN_go], [test "$ax_thrift_gen_go" = "yes"])
 
 # --- Coverage hooks ---
 
@@ -444,6 +494,7 @@
 echo "Building Perl Library ........ : $have_perl"
 echo "Building PHP Library ......... : $have_php"
 echo "Building Erlang Library ...... : $have_erlang"
+echo "Building Go Library .......... : $have_go"
 if test "$have_cpp" = "yes" ; then
   echo
   echo "Building TZlibTransport ...... : $have_zlib"
@@ -485,6 +536,14 @@
   echo
   echo "Using erlc ................... : $ERLC"
 fi
+if test "$have_go" = "yes" ; then
+  echo
+  echo "Using GOROOT.................. : $GOROOT"
+  echo "Using GOBIN................... : $GOBIN"
+  echo "Using GOARCH.................. : $GOARCH"
+  echo "Using GO Compiler............. : $GO_C"
+  echo "Using GO Linker............... : $GO_L"
+fi
 echo
 echo "If something is missing that you think should be present,"
 echo "please skim the output of configure to find the missing"
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 9dbc1c1..8538afa 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -66,4 +66,5 @@
   ocaml \
   js \
   as3 \
-  st
+  st \
+  go
diff --git a/lib/go/Make.deps b/lib/go/Make.deps
new file mode 100644
index 0000000..c233e7e
--- /dev/null
+++ b/lib/go/Make.deps
@@ -0,0 +1,134 @@
+thrift/.install: bufio.install bytes.install container/list.install container/vector.install encoding/base64.install encoding/binary.install fmt.install http.install io.install json.install log.install math.install net.install os.install reflect.install sort.install strconv.install strings.install
+archive/tar.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/archive/tar.a
+archive/zip.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/archive/zip.a
+asn1.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/asn1.a
+big.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/big.a
+bufio.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/bufio.a
+bytes.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/bytes.a
+cmath.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/cmath.a
+compress/flate.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/compress/flate.a
+compress/gzip.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/compress/gzip.a
+compress/zlib.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/compress/zlib.a
+container/heap.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/container/heap.a
+container/list.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/container/list.a
+container/ring.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/container/ring.a
+container/vector.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/container/vector.a
+crypto.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto.a
+crypto/aes.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/aes.a
+crypto/block.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/block.a
+crypto/blowfish.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/blowfish.a
+crypto/cast5.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/cast5.a
+crypto/cipher.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/cipher.a
+crypto/dsa.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/dsa.a
+crypto/elliptic.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/elliptic.a
+crypto/hmac.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/hmac.a
+crypto/md4.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/md4.a
+crypto/md5.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/md5.a
+crypto/ocsp.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/ocsp.a
+crypto/rand.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/rand.a
+crypto/rc4.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/rc4.a
+crypto/ripemd160.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/ripemd160.a
+crypto/rsa.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/rsa.a
+crypto/sha1.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/sha1.a
+crypto/sha256.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/sha256.a
+crypto/sha512.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/sha512.a
+crypto/subtle.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/subtle.a
+crypto/tls.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/tls.a
+crypto/twofish.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/twofish.a
+crypto/x509.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/x509.a
+crypto/xtea.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/xtea.a
+debug/dwarf.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/debug/dwarf.a
+debug/macho.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/debug/macho.a
+debug/elf.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/debug/elf.a
+debug/gosym.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/debug/gosym.a
+debug/pe.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/debug/pe.a
+debug/proc.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/debug/proc.a
+ebnf.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/ebnf.a
+encoding/ascii85.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/encoding/ascii85.a
+encoding/base32.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/encoding/base32.a
+encoding/base64.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/encoding/base64.a
+encoding/binary.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/encoding/binary.a
+encoding/git85.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/encoding/git85.a
+encoding/hex.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/encoding/hex.a
+encoding/line.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/encoding/line.a
+encoding/pem.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/encoding/pem.a
+exec.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/exec.a
+exp/datafmt.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/exp/datafmt.a
+exp/draw.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/exp/draw.a
+exp/draw/x11.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/exp/draw/x11.a
+exp/eval.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/exp/eval.a
+expvar.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/expvar.a
+flag.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/flag.a
+fmt.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/fmt.a
+go/ast.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/go/ast.a
+go/doc.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/go/doc.a
+go/parser.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/go/parser.a
+go/printer.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/go/printer.a
+go/scanner.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/go/scanner.a
+go/token.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/go/token.a
+go/typechecker.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/go/typechecker.a
+gob.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/gob.a
+hash.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/hash.a
+hash/adler32.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/hash/adler32.a
+hash/crc32.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/hash/crc32.a
+hash/crc64.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/hash/crc64.a
+html.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/html.a
+http.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/http.a
+http/pprof.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/http/pprof.a
+image.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/image.a
+image/jpeg.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/image/jpeg.a
+image/png.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/image/png.a
+index/suffixarray.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/index/suffixarray.a
+io.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/io.a
+io/ioutil.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/io/ioutil.a
+json.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/json.a
+log.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/log.a
+math.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/math.a
+mime.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/mime.a
+mime/multipart.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/mime/multipart.a
+net.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/net.a
+net/dict.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/net/dict.a
+net/textproto.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/net/textproto.a
+netchan.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/netchan.a
+os.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/os.a
+os/signal.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/os/signal.a
+patch.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/patch.a
+path.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/path.a
+rand.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/rand.a
+reflect.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/reflect.a
+regexp.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/regexp.a
+rpc.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/rpc.a
+rpc/jsonrpc.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/rpc/jsonrpc.a
+runtime.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/runtime.a
+runtime/cgo.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/runtime/cgo.a
+runtime/debug.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/runtime/debug.a
+runtime/pprof.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/runtime/pprof.a
+scanner.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/scanner.a
+smtp.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/smtp.a
+sort.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/sort.a
+strconv.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/strconv.a
+strings.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/strings.a
+sync.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/sync.a
+syscall.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/syscall.a
+syslog.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/syslog.a
+tabwriter.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/tabwriter.a
+template.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/template.a
+testing.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/testing.a
+testing/iotest.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/testing/iotest.a
+testing/quick.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/testing/quick.a
+testing/script.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/testing/script.a
+time.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/time.a
+try.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/try.a
+unicode.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/unicode.a
+utf16.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/utf16.a
+utf8.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/utf8.a
+websocket.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/websocket.a
+xml.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/xml.a
+../cmd/cgo.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/../cmd/cgo.a
+../cmd/ebnflint.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/../cmd/ebnflint.a
+../cmd/godoc.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/../cmd/godoc.a
+../cmd/gofmt.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/../cmd/gofmt.a
+../cmd/goinstall.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/../cmd/goinstall.a
+../cmd/govet.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/../cmd/govet.a
+../cmd/goyacc.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/../cmd/goyacc.a
+../cmd/hgpatch.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/../cmd/hgpatch.a
diff --git a/lib/go/Makefile b/lib/go/Makefile
new file mode 100644
index 0000000..8e81d8d
--- /dev/null
+++ b/lib/go/Makefile
@@ -0,0 +1,64 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# After editing the DIRS= list or adding imports to any Go files
+# in any of those directories, run:
+#
+#	./deps.bash
+#
+# to rebuild the dependency information in Make.deps.
+
+
+include $(GOROOT)/src/Make.inc
+
+all: Make.deps install
+
+DIRS=\
+     thrift/\
+
+TEST=\
+	$(filter-out $(NOTEST),$(DIRS))
+
+
+clean.dirs: $(addsuffix .clean, $(DIRS))
+install.dirs: $(addsuffix .install, $(DIRS))
+nuke.dirs: $(addsuffix .nuke, $(DIRS))
+test.dirs: $(addsuffix .test, $(DIRS))
+check.dirs: $(addsuffix .check, $(DIRS))
+
+%.clean:
+	+cd $* && gomake clean
+
+%.install:
+	+cd $* && gomake install
+
+%.nuke:
+	+cd $* && gomake nuke
+
+%.test:
+	+cd $* && gomake test
+
+%.check:
+	+cd $* && gomake check
+
+clean: clean.dirs
+
+install: install.dirs
+
+test:	test.dirs
+
+check:	check.dirs
+
+#nuke: nuke.dirs
+#	rm -rf "$(GOROOT)"/pkg/thrift.*
+
+echo-dirs:
+	@echo $(DIRS)
+
+Make.deps:
+	./deps.bash
+
+deps:
+	./deps.bash
+
diff --git a/lib/go/deps.bash b/lib/go/deps.bash
new file mode 100644
index 0000000..dabd404
--- /dev/null
+++ b/lib/go/deps.bash
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+OUT="Make.deps"
+TMP="Make.deps.tmp"
+
+if [ -f $OUT ] && ! [ -w $OUT ]; then
+	echo "$0: $OUT is read-only; aborting." 1>&2
+	exit 1
+fi
+
+# Get list of directories from Makefile
+dirs=$(sed '1,/^DIRS=/d; /^$/,$d; s/\\//g' Makefile)
+dirs2=$(sed '1,/^DIRS=/d; /^$/,$d; s/\\//g' $GOROOT/src/pkg/Makefile)
+dirpat=$(echo $dirs $dirs2 | sed 's/ /|/g; s/.*/^(&)$/')
+
+for dir in $dirs; do (
+	cd $dir || exit 1
+
+	sources=$(sed -n 's/\.go\\/.go/p' Makefile)
+	sources=$(ls $sources 2> /dev/null)  # remove .s, .c, etc.
+
+	deps=$(
+		sed -n '/^import.*"/p; /^import[ \t]*(/,/^)/p' $sources /dev/null |
+		cut -d '"' -f2 |
+		egrep "$dirpat" |
+		grep -v "^$dir\$" |
+		sed 's/$/.install/' |
+		sort -u
+	)
+
+	echo $dir.install: $deps
+) done > $TMP
+
+for dir in $dirs2; do (
+  echo $dir.install: \${GOROOT}/pkg/\${GOOS}_\${GOARCH}/${dir}.a
+) done >> $TMP
+
+mv $TMP $OUT
diff --git a/lib/go/thrift/Makefile b/lib/go/thrift/Makefile
new file mode 100644
index 0000000..59f7862
--- /dev/null
+++ b/lib/go/thrift/Makefile
@@ -0,0 +1,58 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include $(GOROOT)/src/Make.inc
+
+TARG=thrift
+GOFILES=\
+        tapplication_exception.go\
+        tbase.go\
+        tbinary_protocol.go\
+        tcompact_protocol.go\
+        tcompare.go\
+        tcontainer.go\
+        texception.go\
+        tfield.go\
+        tframed_transport.go\
+        thttp_client.go\
+        tiostream_transport.go\
+        tlist.go\
+        tjson_protocol.go\
+        tmap.go\
+        tmemory_buffer.go\
+        tmessage.go\
+        tmessagetype.go\
+        tnonblocking_server.go\
+        tnonblocking_server_socket.go\
+        tnonblocking_socket.go\
+        tnonblocking_transport.go\
+        tnumeric.go\
+        tprocessor.go\
+        tprocessor_factory.go\
+        tprotocol.go\
+        tprotocol_exception.go\
+        tprotocol_factory.go\
+        tserver.go\
+        tserver_socket.go\
+        tserver_transport.go\
+        tset.go\
+        tsimple_server.go\
+        tsimple_json_protocol.go\
+        tsocket.go\
+        tstruct.go\
+        ttransport.go\
+        ttransport_exception.go\
+        ttransport_factory.go\
+        ttype.go
+
+DIRS=\
+
+include $(GOROOT)/src/Make.pkg
+
+check:
+	gomake test
+
+-include ../Make.deps
+
+
diff --git a/lib/go/thrift/_testmain.go b/lib/go/thrift/_testmain.go
new file mode 100644
index 0000000..3b0abfb
--- /dev/null
+++ b/lib/go/thrift/_testmain.go
@@ -0,0 +1,68 @@
+package main
+
+import "./_xtest_"
+import "testing"
+import __regexp__ "regexp"
+
+var tests = []testing.InternalTest{
+	{"thrift_test.TestTApplicationException", thrift_test.TestTApplicationException},
+	{"thrift_test.TestReadWriteBinaryProtocol", thrift_test.TestReadWriteBinaryProtocol},
+	{"thrift_test.TestReadWriteCompactProtocol", thrift_test.TestReadWriteCompactProtocol},
+	{"thrift_test.TestTException", thrift_test.TestTException},
+	{"thrift_test.TestFramedTransport", thrift_test.TestFramedTransport},
+	{"thrift_test.TestHttpClient", thrift_test.TestHttpClient},
+	{"thrift_test.TestIOStreamTransport", thrift_test.TestIOStreamTransport},
+	{"thrift_test.TestWriteJSONProtocolBool", thrift_test.TestWriteJSONProtocolBool},
+	{"thrift_test.TestReadJSONProtocolBool", thrift_test.TestReadJSONProtocolBool},
+	{"thrift_test.TestWriteJSONProtocolByte", thrift_test.TestWriteJSONProtocolByte},
+	{"thrift_test.TestReadJSONProtocolByte", thrift_test.TestReadJSONProtocolByte},
+	{"thrift_test.TestWriteJSONProtocolI16", thrift_test.TestWriteJSONProtocolI16},
+	{"thrift_test.TestReadJSONProtocolI16", thrift_test.TestReadJSONProtocolI16},
+	{"thrift_test.TestWriteJSONProtocolI32", thrift_test.TestWriteJSONProtocolI32},
+	{"thrift_test.TestReadJSONProtocolI32", thrift_test.TestReadJSONProtocolI32},
+	{"thrift_test.TestWriteJSONProtocolI64", thrift_test.TestWriteJSONProtocolI64},
+	{"thrift_test.TestReadJSONProtocolI64", thrift_test.TestReadJSONProtocolI64},
+	{"thrift_test.TestWriteJSONProtocolDouble", thrift_test.TestWriteJSONProtocolDouble},
+	{"thrift_test.TestReadJSONProtocolDouble", thrift_test.TestReadJSONProtocolDouble},
+	{"thrift_test.TestWriteJSONProtocolString", thrift_test.TestWriteJSONProtocolString},
+	{"thrift_test.TestReadJSONProtocolString", thrift_test.TestReadJSONProtocolString},
+	{"thrift_test.TestWriteJSONProtocolBinary", thrift_test.TestWriteJSONProtocolBinary},
+	{"thrift_test.TestReadJSONProtocolBinary", thrift_test.TestReadJSONProtocolBinary},
+	{"thrift_test.TestWriteJSONProtocolList", thrift_test.TestWriteJSONProtocolList},
+	{"thrift_test.TestWriteJSONProtocolSet", thrift_test.TestWriteJSONProtocolSet},
+	{"thrift_test.TestWriteJSONProtocolMap", thrift_test.TestWriteJSONProtocolMap},
+	{"thrift_test.TestReadWriteJSONStruct", thrift_test.TestReadWriteJSONStruct},
+	{"thrift_test.TestReadWriteJSONProtocol", thrift_test.TestReadWriteJSONProtocol},
+	{"thrift_test.TestMemoryBuffer", thrift_test.TestMemoryBuffer},
+	{"thrift_test.TestNonblockingTransportServerToClient", thrift_test.TestNonblockingTransportServerToClient},
+	{"thrift_test.TestNonblockingTransportClientToServer", thrift_test.TestNonblockingTransportClientToServer},
+	{"thrift_test.TestNothing", thrift_test.TestNothing},
+	{"thrift_test.TestWriteSimpleJSONProtocolBool", thrift_test.TestWriteSimpleJSONProtocolBool},
+	{"thrift_test.TestReadSimpleJSONProtocolBool", thrift_test.TestReadSimpleJSONProtocolBool},
+	{"thrift_test.TestWriteSimpleJSONProtocolByte", thrift_test.TestWriteSimpleJSONProtocolByte},
+	{"thrift_test.TestReadSimpleJSONProtocolByte", thrift_test.TestReadSimpleJSONProtocolByte},
+	{"thrift_test.TestWriteSimpleJSONProtocolI16", thrift_test.TestWriteSimpleJSONProtocolI16},
+	{"thrift_test.TestReadSimpleJSONProtocolI16", thrift_test.TestReadSimpleJSONProtocolI16},
+	{"thrift_test.TestWriteSimpleJSONProtocolI32", thrift_test.TestWriteSimpleJSONProtocolI32},
+	{"thrift_test.TestReadSimpleJSONProtocolI32", thrift_test.TestReadSimpleJSONProtocolI32},
+	{"thrift_test.TestWriteSimpleJSONProtocolI64", thrift_test.TestWriteSimpleJSONProtocolI64},
+	{"thrift_test.TestReadSimpleJSONProtocolI64", thrift_test.TestReadSimpleJSONProtocolI64},
+	{"thrift_test.TestWriteSimpleJSONProtocolDouble", thrift_test.TestWriteSimpleJSONProtocolDouble},
+	{"thrift_test.TestReadSimpleJSONProtocolDouble", thrift_test.TestReadSimpleJSONProtocolDouble},
+	{"thrift_test.TestWriteSimpleJSONProtocolString", thrift_test.TestWriteSimpleJSONProtocolString},
+	{"thrift_test.TestReadSimpleJSONProtocolString", thrift_test.TestReadSimpleJSONProtocolString},
+	{"thrift_test.TestWriteSimpleJSONProtocolBinary", thrift_test.TestWriteSimpleJSONProtocolBinary},
+	{"thrift_test.TestReadSimpleJSONProtocolBinary", thrift_test.TestReadSimpleJSONProtocolBinary},
+	{"thrift_test.TestWriteSimpleJSONProtocolList", thrift_test.TestWriteSimpleJSONProtocolList},
+	{"thrift_test.TestWriteSimpleJSONProtocolSet", thrift_test.TestWriteSimpleJSONProtocolSet},
+	{"thrift_test.TestWriteSimpleJSONProtocolMap", thrift_test.TestWriteSimpleJSONProtocolMap},
+	{"thrift_test.TestReadWriteSimpleJSONStruct", thrift_test.TestReadWriteSimpleJSONStruct},
+	{"thrift_test.TestReadWriteSimpleJSONProtocol", thrift_test.TestReadWriteSimpleJSONProtocol},
+}
+var benchmarks = []testing.InternalBenchmark{ //
+}
+
+func main() {
+	testing.Main(__regexp__.MatchString, tests)
+	testing.RunBenchmarks(__regexp__.MatchString, benchmarks)
+}
diff --git a/lib/go/thrift/tapplication_exception.go b/lib/go/thrift/tapplication_exception.go
new file mode 100644
index 0000000..fc8bf2e
--- /dev/null
+++ b/lib/go/thrift/tapplication_exception.go
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "os"
+)
+
+const (
+  UNKNOWN_APPLICATION_EXCEPTION  = 0
+  UNKNOWN_METHOD                 = 1
+  INVALID_MESSAGE_TYPE_EXCEPTION = 2
+  WRONG_METHOD_NAME              = 3
+  BAD_SEQUENCE_ID                = 4
+  MISSING_RESULT                 = 5
+  INTERNAL_ERROR                 = 6
+  PROTOCOL_ERROR                 = 7
+)
+
+
+/**
+ * Application level exception
+ *
+ */
+type TApplicationException interface {
+  TException
+  TypeId() int32
+  Read(iprot TProtocol) (TApplicationException, os.Error)
+  Write(oprot TProtocol) os.Error
+}
+
+type tApplicationException struct {
+  TException
+  type_ int32
+}
+
+func NewTApplicationExceptionDefault() TApplicationException {
+  return NewTApplicationException(UNKNOWN_APPLICATION_EXCEPTION, "UNKNOWN")
+}
+
+func NewTApplicationExceptionType(type_ int32) TApplicationException {
+  return NewTApplicationException(type_, "UNKNOWN")
+}
+
+func NewTApplicationException(type_ int32, message string) TApplicationException {
+  return &tApplicationException{TException: NewTException(message), type_: type_}
+}
+
+func NewTApplicationExceptionMessage(message string) TApplicationException {
+  return NewTApplicationException(UNKNOWN_APPLICATION_EXCEPTION, message)
+}
+
+func (p *tApplicationException) TypeId() int32 {
+  return p.type_
+}
+
+func (p *tApplicationException) Read(iprot TProtocol) (error TApplicationException, err os.Error) {
+  _, err = iprot.ReadStructBegin()
+  if err != nil {
+    return
+  }
+
+  message := ""
+  type_ := int32(UNKNOWN_APPLICATION_EXCEPTION)
+
+  for {
+    _, ttype, id, err := iprot.ReadFieldBegin()
+    if err != nil {
+      return
+    }
+    if ttype == STOP {
+      break
+    }
+    switch id {
+    case 1:
+      if ttype == STRING {
+        message, err = iprot.ReadString()
+        if err != nil {
+          return
+        }
+      } else {
+        err = SkipDefaultDepth(iprot, ttype)
+        if err != nil {
+          return
+        }
+      }
+      break
+    case 2:
+      if ttype == I32 {
+        type_, err = iprot.ReadI32()
+        if err != nil {
+          return
+        }
+      } else {
+        err = SkipDefaultDepth(iprot, ttype)
+        if err != nil {
+          return
+        }
+      }
+      break
+    default:
+      err = SkipDefaultDepth(iprot, ttype)
+      if err != nil {
+        return
+      }
+      break
+    }
+    err = iprot.ReadFieldEnd()
+    if err != nil {
+      return
+    }
+  }
+  err = iprot.ReadStructEnd()
+  error = NewTApplicationException(type_, message)
+  return
+}
+
+func (p *tApplicationException) Write(oprot TProtocol) (err os.Error) {
+  err = oprot.WriteStructBegin("TApplicationException")
+  if len(p.String()) > 0 {
+    err = oprot.WriteFieldBegin("message", STRING, 1)
+    if err != nil {
+      return
+    }
+    err = oprot.WriteString(p.String())
+    if err != nil {
+      return
+    }
+    err = oprot.WriteFieldEnd()
+    if err != nil {
+      return
+    }
+  }
+  err = oprot.WriteFieldBegin("type", I32, 2)
+  if err != nil {
+    return
+  }
+  err = oprot.WriteI32(p.type_)
+  if err != nil {
+    return
+  }
+  err = oprot.WriteFieldEnd()
+  if err != nil {
+    return
+  }
+  err = oprot.WriteFieldStop()
+  if err != nil {
+    return
+  }
+  err = oprot.WriteStructEnd()
+  return
+}
diff --git a/lib/go/thrift/tapplication_exception_test.go b/lib/go/thrift/tapplication_exception_test.go
new file mode 100644
index 0000000..d9572f4
--- /dev/null
+++ b/lib/go/thrift/tapplication_exception_test.go
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package thrift_test
+
+import (
+  . "thrift"
+  "testing"
+)
+
+func TestTApplicationException(t *testing.T) {
+  exc := NewTApplicationException(UNKNOWN_APPLICATION_EXCEPTION, "")
+  if exc.String() != "" {
+    t.Fatalf("Expected empty string for exception but found '%s'", exc.String())
+  }
+  if exc.TypeId() != UNKNOWN_APPLICATION_EXCEPTION {
+    t.Fatalf("Expected type UNKNOWN for exception but found '%s'", exc.TypeId())
+  }
+  exc = NewTApplicationException(WRONG_METHOD_NAME, "junk_method")
+  if exc.String() != "junk_method" {
+    t.Fatalf("Expected 'junk_method' for exception but found '%s'", exc.String())
+  }
+  if exc.TypeId() != WRONG_METHOD_NAME {
+    t.Fatalf("Expected type WRONG_METHOD_NAME for exception but found '%s'", exc.TypeId())
+  }
+}
diff --git a/lib/go/thrift/tbase.go b/lib/go/thrift/tbase.go
new file mode 100644
index 0000000..adc52d0
--- /dev/null
+++ b/lib/go/thrift/tbase.go
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+/**
+ * Generic base interface for generated Thrift objects.
+ *
+ */
+type TBase interface {
+
+  /**
+   * Reads the TObject from the given input protocol
+   *
+   * @param iprot Input protocol
+   */
+  Read(iprot TProtocol) (err TException)
+
+  /**
+   * Writes the objects out to the protocol
+   *
+   * @param oprot Output protocol
+   */
+  Write(oprot TProtocol) (err TException)
+
+  /**
+   * Check if a field is currently set or unset.
+   *
+   * @param field
+   */
+  IsSet(field TField) bool
+
+  /**
+   * Get a field's value by field variable. Primitive types will be wrapped in 
+   * the appropriate "boxed" types.
+   *
+   * @param field
+   */
+  FieldValue(field TField) interface{}
+
+  /**
+   * Set a field's value by field variable. Primitive types must be "boxed" in
+   * the appropriate object wrapper type.
+   *
+   * @param field
+   */
+  SetFieldValue(field TField, value interface{})
+
+  DeepCopy() TBase
+}
diff --git a/lib/go/thrift/tbinary_protocol.go b/lib/go/thrift/tbinary_protocol.go
new file mode 100644
index 0000000..1c88da6
--- /dev/null
+++ b/lib/go/thrift/tbinary_protocol.go
@@ -0,0 +1,493 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "encoding/binary"
+  "math"
+  "strings"
+  "io"
+)
+
+type TBinaryProtocol struct {
+  //TProtocolBase;
+  trans            TTransport
+  _StrictRead      bool
+  _StrictWrite     bool
+  _ReadLength      int
+  _CheckReadLength bool
+}
+
+type TBinaryProtocolFactory struct {
+  _StrictRead  bool
+  _StrictWrite bool
+}
+
+func NewTBinaryProtocolTransport(t TTransport) *TBinaryProtocol {
+  return NewTBinaryProtocol(t, false, true)
+}
+
+func NewTBinaryProtocol(t TTransport, strictRead, strictWrite bool) *TBinaryProtocol {
+  //return &TBinaryProtocol{TProtocolBase:TProtocolBase{trans:t}, _StrictRead:strictRead, _StrictWrite:strictWrite, _ReadLength:0, _CheckReadLength:false};
+  return &TBinaryProtocol{trans: t, _StrictRead: strictRead, _StrictWrite: strictWrite, _ReadLength: 0, _CheckReadLength: false}
+}
+
+func NewTBinaryProtocolFactoryDefault() *TBinaryProtocolFactory {
+  return NewTBinaryProtocolFactory(false, true)
+}
+
+func NewTBinaryProtocolFactory(strictRead, strictWrite bool) *TBinaryProtocolFactory {
+  return &TBinaryProtocolFactory{_StrictRead: strictRead, _StrictWrite: strictWrite}
+}
+
+func (p *TBinaryProtocolFactory) GetProtocol(t TTransport) TProtocol {
+  return NewTBinaryProtocol(t, p._StrictRead, p._StrictWrite)
+}
+
+/**
+ * Writing Methods
+ */
+
+func (p *TBinaryProtocol) WriteMessageBegin(name string, typeId TMessageType, seqId int32) TProtocolException {
+  if p._StrictWrite {
+    version := uint32(VERSION_1) | uint32(typeId)
+    e := p.WriteI32(int32(version))
+    if e != nil {
+      return e
+    }
+    e = p.WriteString(name)
+    if e != nil {
+      return e
+    }
+    e = p.WriteI32(seqId)
+    return e
+  } else {
+    e := p.WriteString(name)
+    if e != nil {
+      return e
+    }
+    e = p.WriteByte(byte(typeId))
+    if e != nil {
+      return e
+    }
+    e = p.WriteI32(seqId)
+    return e
+  }
+  return nil
+}
+
+func (p *TBinaryProtocol) WriteMessageEnd() TProtocolException {
+  return nil
+}
+
+func (p *TBinaryProtocol) WriteStructBegin(name string) TProtocolException {
+  return nil
+}
+
+func (p *TBinaryProtocol) WriteStructEnd() TProtocolException {
+  return nil
+}
+
+func (p *TBinaryProtocol) WriteFieldBegin(name string, typeId TType, id int16) TProtocolException {
+  e := p.WriteByte(byte(typeId))
+  if e != nil {
+    return e
+  }
+  e = p.WriteI16(id)
+  return e
+}
+
+func (p *TBinaryProtocol) WriteFieldEnd() TProtocolException {
+  return nil
+}
+
+func (p *TBinaryProtocol) WriteFieldStop() TProtocolException {
+  e := p.WriteByte(STOP)
+  return e
+}
+
+func (p *TBinaryProtocol) WriteMapBegin(keyType TType, valueType TType, size int) TProtocolException {
+  e := p.WriteByte(byte(keyType))
+  if e != nil {
+    return e
+  }
+  e = p.WriteByte(byte(valueType))
+  if e != nil {
+    return e
+  }
+  e = p.WriteI32(int32(size))
+  return e
+}
+
+func (p *TBinaryProtocol) WriteMapEnd() TProtocolException {
+  return nil
+}
+
+func (p *TBinaryProtocol) WriteListBegin(elemType TType, size int) TProtocolException {
+  e := p.WriteByte(byte(elemType))
+  if e != nil {
+    return e
+  }
+  e = p.WriteI32(int32(size))
+  return e
+}
+
+func (p *TBinaryProtocol) WriteListEnd() TProtocolException {
+  return nil
+}
+
+func (p *TBinaryProtocol) WriteSetBegin(elemType TType, size int) TProtocolException {
+  e := p.WriteByte(byte(elemType))
+  if e != nil {
+    return e
+  }
+  e = p.WriteI32(int32(size))
+  return e
+}
+
+func (p *TBinaryProtocol) WriteSetEnd() TProtocolException {
+  return nil
+}
+
+func (p *TBinaryProtocol) WriteBool(value bool) TProtocolException {
+  if value {
+    return p.WriteByte(1)
+  }
+  return p.WriteByte(0)
+}
+
+func (p *TBinaryProtocol) WriteByte(value byte) TProtocolException {
+  v := []byte{value}
+  _, e := p.trans.Write(v)
+  return NewTProtocolExceptionFromOsError(e)
+}
+
+func (p *TBinaryProtocol) WriteI16(value int16) TProtocolException {
+  h := byte(0xff & (value >> 8))
+  l := byte(0xff & value)
+  v := []byte{h, l}
+  _, e := p.trans.Write(v)
+  return NewTProtocolExceptionFromOsError(e)
+}
+
+func (p *TBinaryProtocol) WriteI32(value int32) TProtocolException {
+  a := byte(0xff & (value >> 24))
+  b := byte(0xff & (value >> 16))
+  c := byte(0xff & (value >> 8))
+  d := byte(0xff & value)
+  v := []byte{a, b, c, d}
+  _, e := p.trans.Write(v)
+  return NewTProtocolExceptionFromOsError(e)
+}
+
+func (p *TBinaryProtocol) WriteI64(value int64) TProtocolException {
+  a := byte(0xff & (value >> 56))
+  b := byte(0xff & (value >> 48))
+  c := byte(0xff & (value >> 40))
+  d := byte(0xff & (value >> 32))
+  e := byte(0xff & (value >> 24))
+  f := byte(0xff & (value >> 16))
+  g := byte(0xff & (value >> 8))
+  h := byte(0xff & value)
+  v := []byte{a, b, c, d, e, f, g, h}
+  _, err := p.trans.Write(v)
+  return NewTProtocolExceptionFromOsError(err)
+}
+
+func (p *TBinaryProtocol) WriteDouble(value float64) TProtocolException {
+  return p.WriteI64(int64(math.Float64bits(value)))
+}
+
+func (p *TBinaryProtocol) WriteString(value string) TProtocolException {
+  return p.WriteBinaryFromReader(strings.NewReader(value), len(value))
+}
+
+func (p *TBinaryProtocol) WriteBinary(value []byte) TProtocolException {
+  e := p.WriteI32(int32(len(value)))
+  if e != nil {
+    return e
+  }
+  _, err := p.trans.Write(value)
+  return NewTProtocolExceptionFromOsError(err)
+}
+
+func (p *TBinaryProtocol) WriteBinaryFromReader(reader io.Reader, size int) TProtocolException {
+  e := p.WriteI32(int32(size))
+  if e != nil {
+    return e
+  }
+  _, err := io.Copyn(p.trans, reader, int64(size))
+  return NewTProtocolExceptionFromOsError(err)
+}
+
+
+/**
+ * Reading methods
+ */
+
+func (p *TBinaryProtocol) ReadMessageBegin() (name string, typeId TMessageType, seqId int32, err TProtocolException) {
+  size, e := p.ReadI32()
+  if e != nil {
+    return "", typeId, 0, NewTProtocolExceptionFromOsError(e)
+  }
+  if size < 0 {
+    typeId = TMessageType(size & 0x0ff)
+    version := int64(int64(size) & VERSION_MASK)
+    if version != VERSION_1 {
+      return name, typeId, seqId, NewTProtocolException(BAD_VERSION, "Bad version in ReadMessageBegin")
+    }
+    name, e = p.ReadString()
+    if e != nil {
+      return name, typeId, seqId, NewTProtocolExceptionFromOsError(e)
+    }
+    seqId, e = p.ReadI32()
+    if e != nil {
+      return name, typeId, seqId, NewTProtocolExceptionFromOsError(e)
+    }
+    return name, typeId, seqId, nil
+  }
+  if p._StrictRead {
+    return name, typeId, seqId, NewTProtocolException(BAD_VERSION, "Missing version in ReadMessageBegin")
+  }
+  name, e2 := p.readStringBody(int(size))
+  if e2 != nil {
+    return name, typeId, seqId, e2
+  }
+  b, e3 := p.ReadByte()
+  if e3 != nil {
+    return name, typeId, seqId, e3
+  }
+  typeId = TMessageType(b)
+  seqId, e4 := p.ReadI32()
+  if e4 != nil {
+    return name, typeId, seqId, e4
+  }
+  return name, typeId, seqId, nil
+}
+
+func (p *TBinaryProtocol) ReadMessageEnd() TProtocolException {
+  return nil
+}
+
+func (p *TBinaryProtocol) ReadStructBegin() (name string, err TProtocolException) {
+  return
+}
+
+func (p *TBinaryProtocol) ReadStructEnd() TProtocolException {
+  return nil
+}
+
+func (p *TBinaryProtocol) ReadFieldBegin() (name string, typeId TType, seqId int16, err TProtocolException) {
+  t, err := p.ReadByte()
+  typeId = TType(t)
+  if err != nil {
+    return name, typeId, seqId, err
+  }
+  if t != STOP {
+    seqId, err = p.ReadI16()
+  }
+  return name, typeId, seqId, err
+}
+
+func (p *TBinaryProtocol) ReadFieldEnd() TProtocolException {
+  return nil
+}
+
+func (p *TBinaryProtocol) ReadMapBegin() (kType, vType TType, size int, err TProtocolException) {
+  k, e := p.ReadByte()
+  if e != nil {
+    err = NewTProtocolExceptionFromOsError(e)
+    return
+  }
+  kType = TType(k)
+  v, e := p.ReadByte()
+  if e != nil {
+    err = NewTProtocolExceptionFromOsError(e)
+    return
+  }
+  vType = TType(v)
+  size32, e := p.ReadI32()
+  size = int(size32)
+  if e != nil {
+    err = NewTProtocolExceptionFromOsError(e)
+    return
+  }
+  return kType, vType, size, nil
+}
+
+func (p *TBinaryProtocol) ReadMapEnd() TProtocolException {
+  return nil
+}
+
+func (p *TBinaryProtocol) ReadListBegin() (elemType TType, size int, err TProtocolException) {
+  b, e := p.ReadByte()
+  if e != nil {
+    err = NewTProtocolExceptionFromOsError(e)
+    return
+  }
+  elemType = TType(b)
+  size32, e := p.ReadI32()
+  size = int(size32)
+  if e != nil {
+    err = NewTProtocolExceptionFromOsError(e)
+    return
+  }
+  return elemType, size, nil
+}
+
+func (p *TBinaryProtocol) ReadListEnd() TProtocolException {
+  return nil
+}
+
+func (p *TBinaryProtocol) ReadSetBegin() (elemType TType, size int, err TProtocolException) {
+  b, e := p.ReadByte()
+  if e != nil {
+    err = NewTProtocolExceptionFromOsError(e)
+    return
+  }
+  elemType = TType(b)
+  size32, e := p.ReadI32()
+  size = int(size32)
+  if e != nil {
+    err = NewTProtocolExceptionFromOsError(e)
+    return
+  }
+  return elemType, size, nil
+}
+
+func (p *TBinaryProtocol) ReadSetEnd() TProtocolException {
+  return nil
+}
+
+func (p *TBinaryProtocol) ReadBool() (bool, TProtocolException) {
+  b, e := p.ReadByte()
+  v := true
+  if b != 1 {
+    v = false
+  }
+  return v, e
+}
+
+func (p *TBinaryProtocol) ReadByte() (value byte, err TProtocolException) {
+  buf := []byte{0}
+  err = p.readAll(buf)
+  return buf[0], err
+}
+
+func (p *TBinaryProtocol) ReadI16() (value int16, err TProtocolException) {
+  buf := []byte{0, 0}
+  err = p.readAll(buf)
+  value = int16(binary.BigEndian.Uint16(buf))
+  return value, err
+}
+
+func (p *TBinaryProtocol) ReadI32() (value int32, err TProtocolException) {
+  buf := []byte{0, 0, 0, 0}
+  err = p.readAll(buf)
+  value = int32(binary.BigEndian.Uint32(buf))
+  return value, err
+}
+
+func (p *TBinaryProtocol) ReadI64() (value int64, err TProtocolException) {
+  buf := []byte{0, 0, 0, 0, 0, 0, 0, 0}
+  err = p.readAll(buf)
+  value = int64(binary.BigEndian.Uint64(buf))
+  return value, err
+}
+
+func (p *TBinaryProtocol) ReadDouble() (value float64, err TProtocolException) {
+  buf := []byte{0, 0, 0, 0, 0, 0, 0, 0}
+  err = p.readAll(buf)
+  value = math.Float64frombits(binary.BigEndian.Uint64(buf))
+  return value, err
+}
+
+func (p *TBinaryProtocol) ReadString() (value string, err TProtocolException) {
+  size, e := p.ReadI32()
+  if e != nil {
+    return "", e
+  }
+  return p.readStringBody(int(size))
+}
+
+func (p *TBinaryProtocol) ReadBinary() ([]byte, TProtocolException) {
+  size, e := p.ReadI32()
+  if e != nil {
+    return nil, e
+  }
+  isize := int(size)
+  e = p.checkReadLength(isize)
+  if e != nil {
+    return nil, e
+  }
+  buf := make([]byte, isize)
+  _, err := p.trans.ReadAll(buf)
+  return buf, NewTProtocolExceptionFromOsError(err)
+}
+
+func (p *TBinaryProtocol) Flush() (err TProtocolException) {
+  return NewTProtocolExceptionFromOsError(p.trans.Flush())
+}
+
+func (p *TBinaryProtocol) Skip(fieldType TType) (err TProtocolException) {
+  return SkipDefaultDepth(p, fieldType)
+}
+
+func (p *TBinaryProtocol) Transport() TTransport {
+  return p.trans
+}
+
+func (p *TBinaryProtocol) readAll(buf []byte) TProtocolException {
+  e := p.checkReadLength(len(buf))
+  if e != nil {
+    return e
+  }
+  _, err := p.trans.ReadAll(buf)
+  return NewTProtocolExceptionFromOsError(err)
+}
+
+func (p *TBinaryProtocol) setReadLength(readLength int) {
+  p._ReadLength = readLength
+  p._CheckReadLength = true
+}
+
+func (p *TBinaryProtocol) checkReadLength(length int) TProtocolException {
+  if p._CheckReadLength {
+    p._ReadLength = p._ReadLength - length
+    if p._ReadLength < 0 {
+      return NewTProtocolException(UNKNOWN_PROTOCOL_EXCEPTION, "Message length exceeded: "+string(length))
+    }
+  }
+  return nil
+}
+
+func (p *TBinaryProtocol) readStringBody(size int) (value string, err TProtocolException) {
+  if size < 0 {
+    return "", nil
+  }
+  err = p.checkReadLength(size)
+  if err != nil {
+    return "", err
+  }
+  isize := int(size)
+  buf := make([]byte, isize)
+  _, e := p.trans.ReadAll(buf)
+  return string(buf), NewTProtocolExceptionFromOsError(e)
+}
diff --git a/lib/go/thrift/tbinary_protocol_test.go b/lib/go/thrift/tbinary_protocol_test.go
new file mode 100644
index 0000000..b21b248
--- /dev/null
+++ b/lib/go/thrift/tbinary_protocol_test.go
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package thrift_test
+
+import (
+  . "thrift"
+  "testing"
+  //"bytes";
+)
+
+
+func TestReadWriteBinaryProtocol(t *testing.T) {
+  ReadWriteProtocolTest(t, NewTBinaryProtocolFactoryDefault())
+}
diff --git a/lib/go/thrift/tcompact_protocol.go b/lib/go/thrift/tcompact_protocol.go
new file mode 100644
index 0000000..9b780f7
--- /dev/null
+++ b/lib/go/thrift/tcompact_protocol.go
@@ -0,0 +1,856 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "container/vector"
+  "encoding/binary"
+  "fmt"
+  "math"
+  "os"
+  "strings"
+)
+
+const (
+  COMPACT_PROTOCOL_ID       = 0x082
+  COMPACT_VERSION           = 1
+  COMPACT_VERSION_MASK      = 0x1f
+  COMPACT_TYPE_MASK         = 0x0E0
+  COMPACT_TYPE_SHIFT_AMOUNT = 5
+)
+
+type TCompactType byte
+
+const (
+  COMPACT_BOOLEAN_TRUE  = 0x01
+  COMPACT_BOOLEAN_FALSE = 0x02
+  COMPACT_BYTE          = 0x03
+  COMPACT_I16           = 0x04
+  COMPACT_I32           = 0x05
+  COMPACT_I64           = 0x06
+  COMPACT_DOUBLE        = 0x07
+  COMPACT_BINARY        = 0x08
+  COMPACT_LIST          = 0x09
+  COMPACT_SET           = 0x0A
+  COMPACT_MAP           = 0x0B
+  COMPACT_STRUCT        = 0x0C
+)
+
+var (
+  _TTypeToCompactType []TCompactType
+  _TSTOP              TField
+)
+
+func init() {
+  _TSTOP = NewTField("", STOP, 0)
+  _TTypeToCompactType = make([]TCompactType, int(UTF16)+1)
+  _TTypeToCompactType[int(STOP)] = STOP
+  _TTypeToCompactType[int(BOOL)] = COMPACT_BOOLEAN_TRUE
+  _TTypeToCompactType[int(BYTE)] = COMPACT_BYTE
+  _TTypeToCompactType[int(I16)] = COMPACT_I16
+  _TTypeToCompactType[int(I32)] = COMPACT_I32
+  _TTypeToCompactType[int(I64)] = COMPACT_I64
+  _TTypeToCompactType[int(DOUBLE)] = COMPACT_DOUBLE
+  _TTypeToCompactType[int(STRING)] = COMPACT_BINARY
+  _TTypeToCompactType[int(LIST)] = COMPACT_LIST
+  _TTypeToCompactType[int(SET)] = COMPACT_SET
+  _TTypeToCompactType[int(MAP)] = COMPACT_MAP
+  _TTypeToCompactType[int(STRUCT)] = COMPACT_STRUCT
+}
+
+type TCompactProtocolFactory struct{}
+
+func NewTCompactProtocolFactory() *TCompactProtocolFactory {
+  return &TCompactProtocolFactory{}
+}
+
+func (p *TCompactProtocolFactory) GetProtocol(trans TTransport) TProtocol {
+  return NewTCompactProtocol(trans)
+}
+
+type TCompactProtocol struct {
+  trans TTransport
+
+  /** 
+   * Used to keep track of the last field for the current and previous structs,
+   * so we can do the delta stuff.
+   */
+  lastField   *vector.IntVector
+  lastFieldId int
+
+  /** 
+   * If we encounter a boolean field begin, save the TField here so it can 
+   * have the value incorporated.
+   */
+  booleanField TField
+
+  /**
+   * If we read a field header, and it's a boolean field, save the boolean 
+   * value here so that readBool can use it.
+   */
+  boolValue          bool
+  boolValueIsNotNull bool
+}
+
+/**
+ * Create a TCompactProtocol.
+ *
+ * @param transport the TTransport object to read from or write to.
+ */
+func NewTCompactProtocol(trans TTransport) *TCompactProtocol {
+  return &TCompactProtocol{trans: trans, lastField: &vector.IntVector{}}
+}
+
+
+//
+// Public Writing methods.
+//
+
+/**
+ * Write a message header to the wire. Compact Protocol messages contain the
+ * protocol version so we can migrate forwards in the future if need be.
+ */
+func (p *TCompactProtocol) WriteMessageBegin(name string, typeId TMessageType, seqid int32) TProtocolException {
+  _, err := p.writeByteDirect(COMPACT_PROTOCOL_ID)
+  if err != nil {
+    return NewTProtocolExceptionFromOsError(err)
+  }
+  _, err = p.writeByteDirect((COMPACT_VERSION & COMPACT_VERSION_MASK) | ((byte(typeId) << COMPACT_TYPE_SHIFT_AMOUNT) & COMPACT_TYPE_MASK))
+  if err != nil {
+    return NewTProtocolExceptionFromOsError(err)
+  }
+  _, err = p.writeVarint32(seqid)
+  if err != nil {
+    return NewTProtocolExceptionFromOsError(err)
+  }
+  e := p.WriteString(name)
+  return e
+
+}
+
+func (p *TCompactProtocol) WriteMessageEnd() TProtocolException { return nil }
+
+/**
+ * Write a struct begin. This doesn't actually put anything on the wire. We 
+ * use it as an opportunity to put special placeholder markers on the field
+ * stack so we can get the field id deltas correct.
+ */
+func (p *TCompactProtocol) WriteStructBegin(name string) TProtocolException {
+  p.lastField.Push(p.lastFieldId)
+  p.lastFieldId = 0
+  return nil
+}
+
+/**
+ * Write a struct end. This doesn't actually put anything on the wire. We use
+ * this as an opportunity to pop the last field from the current struct off
+ * of the field stack.
+ */
+func (p *TCompactProtocol) WriteStructEnd() TProtocolException {
+  p.lastFieldId = p.lastField.Pop()
+  return nil
+}
+
+func (p *TCompactProtocol) WriteFieldBegin(name string, typeId TType, id int16) TProtocolException {
+  if typeId == BOOL {
+    // we want to possibly include the value, so we'll wait.
+    p.booleanField = NewTField(name, typeId, int(id))
+    return nil
+  }
+  _, err := p.writeFieldBeginInternal(name, typeId, id, 0xFF)
+  return NewTProtocolExceptionFromOsError(err)
+}
+
+
+/**
+ * The workhorse of writeFieldBegin. It has the option of doing a 
+ * 'type override' of the type header. This is used specifically in the 
+ * boolean field case.
+ */
+func (p *TCompactProtocol) writeFieldBeginInternal(name string, typeId TType, id int16, typeOverride byte) (int, os.Error) {
+  // short lastField = lastField_.pop();
+
+  // if there's a type override, use that.
+  var typeToWrite byte
+  if typeOverride == 0xFF {
+    typeToWrite = byte(p.getCompactType(typeId))
+  } else {
+    typeToWrite = typeOverride
+  }
+  // check if we can use delta encoding for the field id
+  fieldId := int(id)
+  written := 0
+  if fieldId > p.lastFieldId && fieldId-p.lastFieldId <= 15 {
+    // write them together
+    written, err := p.writeByteDirect(byte((fieldId-p.lastFieldId)<<4) | typeToWrite)
+    if err != nil {
+      return written, err
+    }
+  } else {
+    // write them separate
+    n, err := p.writeByteDirect(typeToWrite)
+    if err != nil {
+      return n, err
+    }
+    err = p.WriteI16(id)
+    written = n + 2
+    if err != nil {
+      return written, err
+    }
+  }
+
+  p.lastFieldId = fieldId
+  // p.lastField.Push(field.id);
+  return written, nil
+}
+
+
+func (p *TCompactProtocol) WriteFieldEnd() TProtocolException { return nil }
+
+func (p *TCompactProtocol) WriteFieldStop() TProtocolException {
+  _, err := p.writeByteDirect(STOP)
+  return NewTProtocolExceptionFromOsError(err)
+}
+
+func (p *TCompactProtocol) WriteMapBegin(keyType TType, valueType TType, size int) TProtocolException {
+  if size == 0 {
+    _, err := p.writeByteDirect(0)
+    return NewTProtocolExceptionFromOsError(err)
+  }
+  _, err := p.writeVarint32(int32(size))
+  if err != nil {
+    return NewTProtocolExceptionFromOsError(err)
+  }
+  _, err = p.writeByteDirect(byte(p.getCompactType(keyType))<<4 | byte(p.getCompactType(valueType)))
+  return NewTProtocolExceptionFromOsError(err)
+}
+
+func (p *TCompactProtocol) WriteMapEnd() TProtocolException { return nil }
+
+/**
+ * Write a list header.
+ */
+func (p *TCompactProtocol) WriteListBegin(elemType TType, size int) TProtocolException {
+  _, err := p.writeCollectionBegin(elemType, size)
+  return NewTProtocolExceptionFromOsError(err)
+}
+
+func (p *TCompactProtocol) WriteListEnd() TProtocolException { return nil }
+
+/**
+ * Write a set header.
+ */
+func (p *TCompactProtocol) WriteSetBegin(elemType TType, size int) TProtocolException {
+  _, err := p.writeCollectionBegin(elemType, size)
+  return NewTProtocolExceptionFromOsError(err)
+}
+
+func (p *TCompactProtocol) WriteSetEnd() TProtocolException { return nil }
+
+func (p *TCompactProtocol) WriteBool(value bool) TProtocolException {
+  v := byte(COMPACT_BOOLEAN_FALSE)
+  if value {
+    v = byte(COMPACT_BOOLEAN_TRUE)
+  }
+  if p.booleanField != nil {
+    // we haven't written the field header yet
+    _, err := p.writeFieldBeginInternal(p.booleanField.Name(), p.booleanField.TypeId(), int16(p.booleanField.Id()), v)
+    p.booleanField = nil
+    return NewTProtocolExceptionFromOsError(err)
+  }
+  // we're not part of a field, so just write the value.
+  _, err := p.writeByteDirect(v)
+  return NewTProtocolExceptionFromOsError(err)
+}
+
+/** 
+ * Write a byte. Nothing to see here!
+ */
+func (p *TCompactProtocol) WriteByte(value byte) TProtocolException {
+  _, err := p.writeByteDirect(value)
+  return NewTProtocolExceptionFromOsError(err)
+}
+
+/**
+ * Write an I16 as a zigzag varint.
+ */
+func (p *TCompactProtocol) WriteI16(value int16) TProtocolException {
+  _, err := p.writeVarint32(p.int32ToZigzag(int32(value)))
+  return NewTProtocolExceptionFromOsError(err)
+}
+
+/**
+ * Write an i32 as a zigzag varint.
+ */
+func (p *TCompactProtocol) WriteI32(value int32) TProtocolException {
+  _, err := p.writeVarint32(p.int32ToZigzag(value))
+  return NewTProtocolExceptionFromOsError(err)
+}
+
+/**
+ * Write an i64 as a zigzag varint.
+ */
+func (p *TCompactProtocol) WriteI64(value int64) TProtocolException {
+  _, err := p.writeVarint64(p.int64ToZigzag(value))
+  return NewTProtocolExceptionFromOsError(err)
+}
+
+/**
+ * Write a double to the wire as 8 bytes.
+ */
+func (p *TCompactProtocol) WriteDouble(value float64) TProtocolException {
+  buf := make([]byte, 8)
+  binary.LittleEndian.PutUint64(buf, math.Float64bits(value))
+  _, err := p.trans.Write(buf)
+  return NewTProtocolExceptionFromOsError(err)
+}
+
+/**
+ * Write a string to the wire with a varint size preceeding.
+ */
+func (p *TCompactProtocol) WriteString(value string) TProtocolException {
+  buf := make([]byte, len(value))
+  strings.NewReader(value).Read(buf)
+  return p.WriteBinary(buf)
+}
+
+/**
+ * Write a byte array, using a varint for the size. 
+ */
+func (p *TCompactProtocol) WriteBinary(bin []byte) TProtocolException {
+  _, e := p.writeVarint32(int32(len(bin)))
+  if e != nil {
+    return NewTProtocolExceptionFromOsError(e)
+  }
+  if len(bin) > 0 {
+    _, e = p.trans.Write(bin)
+    return NewTProtocolExceptionFromOsError(e)
+  }
+  return nil
+}
+
+
+// 
+// Reading methods.
+// 
+
+/**
+ * Read a message header. 
+ */
+func (p *TCompactProtocol) ReadMessageBegin() (name string, typeId TMessageType, seqId int32, err TProtocolException) {
+  protocolId, err := p.ReadByte()
+  if protocolId != COMPACT_PROTOCOL_ID {
+    s := fmt.Sprintf("Expected protocol id %02x but got %02x", COMPACT_PROTOCOL_ID, protocolId)
+    return "", typeId, seqId, NewTProtocolException(BAD_VERSION, s)
+  }
+  versionAndType, err := p.ReadByte()
+  version := versionAndType & COMPACT_VERSION_MASK
+  typeId = TMessageType((versionAndType >> COMPACT_TYPE_SHIFT_AMOUNT) & 0x03)
+  if err != nil {
+    return
+  }
+  if version != COMPACT_VERSION {
+    s := fmt.Sprintf("Expected version %02x but got %02x", COMPACT_VERSION, version)
+    err = NewTProtocolException(BAD_VERSION, s)
+    return
+  }
+  seqId, e := p.readVarint32()
+  if e != nil {
+    err = NewTProtocolExceptionFromOsError(e)
+    return
+  }
+  name, err = p.ReadString()
+  return
+}
+
+func (p *TCompactProtocol) ReadMessageEnd() TProtocolException { return nil }
+
+/**
+ * Read a struct begin. There's nothing on the wire for this, but it is our
+ * opportunity to push a new struct begin marker onto the field stack.
+ */
+func (p *TCompactProtocol) ReadStructBegin() (name string, err TProtocolException) {
+  p.lastField.Push(p.lastFieldId)
+  p.lastFieldId = 0
+  return
+}
+
+/**
+ * Doesn't actually consume any wire data, just removes the last field for 
+ * this struct from the field stack.
+ */
+func (p *TCompactProtocol) ReadStructEnd() TProtocolException {
+  // consume the last field we read off the wire.
+  p.lastFieldId = p.lastField.Pop()
+  return nil
+}
+
+/**
+ * Read a field header off the wire. 
+ */
+func (p *TCompactProtocol) ReadFieldBegin() (name string, typeId TType, id int16, err TProtocolException) {
+  t, err := p.ReadByte()
+  if err != nil {
+    return
+  }
+
+  // if it's a stop, then we can return immediately, as the struct is over.
+  if (t & 0x0f) == STOP {
+    return _TSTOP.Name(), _TSTOP.TypeId(), int16(_TSTOP.Id()), nil
+  }
+
+  // mask off the 4 MSB of the type header. it could contain a field id delta.
+  modifier := int16((t & 0xf0) >> 4)
+  if modifier == 0 {
+    // not a delta. look ahead for the zigzag varint field id.
+    id, err = p.ReadI16()
+    if err != nil {
+      return
+    }
+  } else {
+    // has a delta. add the delta to the last read field id.
+    id = int16(p.lastFieldId) + modifier
+  }
+  typeId, e := p.getTType(TCompactType(t & 0x0f))
+  if e != nil {
+    err = NewTProtocolExceptionFromOsError(e)
+    return
+  }
+
+  // if this happens to be a boolean field, the value is encoded in the type
+  if p.isBoolType(t) {
+    // save the boolean value in a special instance variable.
+    p.boolValue = (byte(t)&0x0f == COMPACT_BOOLEAN_TRUE)
+    p.boolValueIsNotNull = true
+  }
+
+  // push the new field onto the field stack so we can keep the deltas going.
+  p.lastFieldId = int(id)
+  return
+}
+
+func (p *TCompactProtocol) ReadFieldEnd() TProtocolException { return nil }
+
+/** 
+ * Read a map header off the wire. If the size is zero, skip reading the key
+ * and value type. This means that 0-length maps will yield TMaps without the
+ * "correct" types.
+ */
+func (p *TCompactProtocol) ReadMapBegin() (keyType TType, valueType TType, size int, err TProtocolException) {
+  size32, e := p.readVarint32()
+  size = int(size32)
+  if e != nil {
+    err = NewTProtocolExceptionFromOsError(e)
+    return
+  }
+  keyAndValueType := byte(STOP)
+  if size != 0 {
+    keyAndValueType, err = p.ReadByte()
+    if err != nil {
+      return
+    }
+  }
+  keyType, _ = p.getTType(TCompactType(keyAndValueType >> 4))
+  valueType, _ = p.getTType(TCompactType(keyAndValueType & 0xf))
+  return
+}
+
+func (p *TCompactProtocol) ReadMapEnd() TProtocolException { return nil }
+
+/**
+ * Read a list header off the wire. If the list size is 0-14, the size will 
+ * be packed into the element type header. If it's a longer list, the 4 MSB
+ * of the element type header will be 0xF, and a varint will follow with the
+ * true size.
+ */
+func (p *TCompactProtocol) ReadListBegin() (elemType TType, size int, err TProtocolException) {
+  size_and_type, err := p.ReadByte()
+  if err != nil {
+    return
+  }
+  size = int((size_and_type >> 4) & 0x0f)
+  if size == 15 {
+    size2, e := p.readVarint32()
+    if e != nil {
+      err = NewTProtocolExceptionFromOsError(e)
+      return
+    }
+    size = int(size2)
+  }
+  elemType, e := p.getTType(TCompactType(size_and_type))
+  if e != nil {
+    err = NewTProtocolExceptionFromOsError(e)
+    return
+  }
+  return
+}
+
+func (p *TCompactProtocol) ReadListEnd() TProtocolException { return nil }
+
+/**
+ * Read a set header off the wire. If the set size is 0-14, the size will 
+ * be packed into the element type header. If it's a longer set, the 4 MSB
+ * of the element type header will be 0xF, and a varint will follow with the
+ * true size.
+ */
+func (p *TCompactProtocol) ReadSetBegin() (elemType TType, size int, err TProtocolException) {
+  return p.ReadListBegin()
+}
+
+func (p *TCompactProtocol) ReadSetEnd() TProtocolException { return nil }
+
+/**
+ * Read a boolean off the wire. If this is a boolean field, the value should
+ * already have been read during readFieldBegin, so we'll just consume the
+ * pre-stored value. Otherwise, read a byte.
+ */
+func (p *TCompactProtocol) ReadBool() (value bool, err TProtocolException) {
+  if p.boolValueIsNotNull {
+    p.boolValueIsNotNull = false
+    return p.boolValue, nil
+  }
+  v, err := p.ReadByte()
+  return v == COMPACT_BOOLEAN_TRUE, err
+}
+
+/**
+ * Read a single byte off the wire. Nothing interesting here.
+ */
+func (p *TCompactProtocol) ReadByte() (value byte, err TProtocolException) {
+  buf := []byte{0}
+  _, e := p.trans.ReadAll(buf)
+  if e != nil {
+    return 0, NewTProtocolExceptionFromOsError(e)
+  }
+  return buf[0], nil
+}
+
+/**
+ * Read an i16 from the wire as a zigzag varint.
+ */
+func (p *TCompactProtocol) ReadI16() (value int16, err TProtocolException) {
+  v, err := p.ReadI32()
+  return int16(v), err
+}
+
+/**
+ * Read an i32 from the wire as a zigzag varint.
+ */
+func (p *TCompactProtocol) ReadI32() (value int32, err TProtocolException) {
+  v, e := p.readVarint32()
+  if e != nil {
+    return 0, NewTProtocolExceptionFromOsError(e)
+  }
+  value = p.zigzagToInt32(v)
+  return value, nil
+}
+
+/**
+ * Read an i64 from the wire as a zigzag varint.
+ */
+func (p *TCompactProtocol) ReadI64() (value int64, err TProtocolException) {
+  v, e := p.readVarint64()
+  if e != nil {
+    return 0, NewTProtocolExceptionFromOsError(e)
+  }
+  value = p.zigzagToInt64(v)
+  return value, nil
+}
+
+/**
+ * No magic here - just read a double off the wire.
+ */
+func (p *TCompactProtocol) ReadDouble() (value float64, err TProtocolException) {
+  longBits := make([]byte, 8)
+  _, e := p.trans.ReadAll(longBits)
+  if e != nil {
+    return 0.0, NewTProtocolExceptionFromOsError(e)
+  }
+  return math.Float64frombits(p.bytesToUint64(longBits)), nil
+}
+
+/**
+ * Reads a []byte (via readBinary), and then UTF-8 decodes it.
+ */
+func (p *TCompactProtocol) ReadString() (value string, err TProtocolException) {
+  v, e := p.ReadBinary()
+  return string(v), NewTProtocolExceptionFromOsError(e)
+}
+
+/**
+ * Read a []byte from the wire. 
+ */
+func (p *TCompactProtocol) ReadBinary() (value []byte, err TProtocolException) {
+  length, e := p.readVarint32()
+  if e != nil {
+    return []byte{}, NewTProtocolExceptionFromOsError(e)
+  }
+  if length == 0 {
+    return []byte{}, nil
+  }
+
+  buf := make([]byte, length)
+  p.trans.ReadAll(buf)
+  return buf, nil
+}
+
+func (p *TCompactProtocol) Flush() (err TProtocolException) {
+  return NewTProtocolExceptionFromOsError(p.trans.Flush())
+}
+
+func (p *TCompactProtocol) Skip(fieldType TType) (err TProtocolException) {
+  return SkipDefaultDepth(p, fieldType)
+}
+
+func (p *TCompactProtocol) Transport() TTransport {
+  return p.trans
+}
+
+//
+// Internal writing methods
+//
+
+/**
+ * Abstract method for writing the start of lists and sets. List and sets on 
+ * the wire differ only by the type indicator.
+ */
+func (p *TCompactProtocol) writeCollectionBegin(elemType TType, size int) (int, os.Error) {
+  if size <= 14 {
+    return p.writeByteDirect(byte(int32(size<<4) | int32(p.getCompactType(elemType))))
+  }
+  n, err := p.writeByteDirect(0xf0 | byte(p.getCompactType(elemType)))
+  if err != nil {
+    return n, err
+  }
+  m, err := p.writeVarint32(int32(size))
+  return n + m, err
+}
+
+/**
+ * Write an i32 as a varint. Results in 1-5 bytes on the wire.
+ * TODO(pomack): make a permanent buffer like writeVarint64?
+ */
+func (p *TCompactProtocol) writeVarint32(n int32) (int, os.Error) {
+  i32buf := make([]byte, 5)
+  idx := 0
+  for {
+    if (n & ^0x7F) == 0 {
+      i32buf[idx] = byte(n)
+      idx++
+      // p.writeByteDirect(byte(n));
+      break
+      // return;
+    } else {
+      i32buf[idx] = byte((n & 0x7F) | 0x80)
+      idx++
+      // p.writeByteDirect(byte(((n & 0x7F) | 0x80)));
+      u := uint32(n)
+      n = int32(u >> 7)
+    }
+  }
+  return p.trans.Write(i32buf[0:idx])
+}
+
+/**
+ * Write an i64 as a varint. Results in 1-10 bytes on the wire.
+ */
+func (p *TCompactProtocol) writeVarint64(n int64) (int, os.Error) {
+  varint64out := make([]byte, 10)
+  idx := 0
+  for {
+    if (n & ^0x7F) == 0 {
+      varint64out[idx] = byte(n)
+      idx++
+      break
+    } else {
+      varint64out[idx] = byte((n & 0x7F) | 0x80)
+      idx++
+      u := uint64(n)
+      n = int64(u >> 7)
+    }
+  }
+  return p.trans.Write(varint64out[0:idx])
+}
+
+/**
+ * Convert l into a zigzag long. This allows negative numbers to be 
+ * represented compactly as a varint.
+ */
+func (p *TCompactProtocol) int64ToZigzag(l int64) int64 {
+  return (l << 1) ^ (l >> 63)
+}
+
+/**
+ * Convert l into a zigzag long. This allows negative numbers to be 
+ * represented compactly as a varint.
+ */
+func (p *TCompactProtocol) int32ToZigzag(n int32) int32 {
+  return (n << 1) ^ (n >> 31)
+}
+
+func (p *TCompactProtocol) fixedUint64ToBytes(n uint64, buf []byte) {
+  binary.LittleEndian.PutUint64(buf, n)
+}
+
+func (p *TCompactProtocol) fixedInt64ToBytes(n int64, buf []byte) {
+  binary.LittleEndian.PutUint64(buf, uint64(n))
+}
+
+/** 
+ * Writes a byte without any possiblity of all that field header nonsense. 
+ * Used internally by other writing methods that know they need to write a byte.
+ */
+func (p *TCompactProtocol) writeByteDirect(b byte) (int, os.Error) {
+  return p.trans.Write([]byte{b})
+}
+
+/** 
+ * Writes a byte without any possiblity of all that field header nonsense.
+ */
+func (p *TCompactProtocol) writeIntAsByteDirect(n int) (int, os.Error) {
+  return p.writeByteDirect(byte(n))
+}
+
+
+//
+// Internal reading methods
+//
+
+/**
+ * Read an i32 from the wire as a varint. The MSB of each byte is set
+ * if there is another byte to follow. This can read up to 5 bytes.
+ */
+func (p *TCompactProtocol) readVarint32() (int32, os.Error) {
+  // if the wire contains the right stuff, this will just truncate the i64 we
+  // read and get us the right sign.
+  v, err := p.readVarint64()
+  return int32(v), err
+}
+
+
+/**
+ * Read an i64 from the wire as a proper varint. The MSB of each byte is set 
+ * if there is another byte to follow. This can read up to 10 bytes.
+ */
+func (p *TCompactProtocol) readVarint64() (int64, os.Error) {
+  shift := uint(0)
+  result := int64(0)
+  for {
+    b, err := p.ReadByte()
+    if err != nil {
+      return 0, err
+    }
+    result |= int64(b&0x7f) << shift
+    if (b & 0x80) != 0x80 {
+      break
+    }
+    shift += 7
+  }
+  return result, nil
+}
+
+
+//
+// encoding helpers
+//
+
+/**
+ * Convert from zigzag int to int.
+ */
+func (p *TCompactProtocol) zigzagToInt32(n int32) int32 {
+  u := uint32(n)
+  return int32(u>>1) ^ -(n & 1)
+}
+
+/** 
+ * Convert from zigzag long to long.
+ */
+func (p *TCompactProtocol) zigzagToInt64(n int64) int64 {
+  u := uint64(n)
+  return int64(u>>1) ^ -(n & 1)
+}
+
+/**
+ * Note that it's important that the mask bytes are long literals, 
+ * otherwise they'll default to ints, and when you shift an int left 56 bits,
+ * you just get a messed up int.
+ */
+func (p *TCompactProtocol) bytesToInt64(b []byte) int64 {
+  return int64(binary.LittleEndian.Uint64(b))
+}
+
+/**
+ * Note that it's important that the mask bytes are long literals, 
+ * otherwise they'll default to ints, and when you shift an int left 56 bits,
+ * you just get a messed up int.
+ */
+func (p *TCompactProtocol) bytesToUint64(b []byte) uint64 {
+  return binary.LittleEndian.Uint64(b)
+}
+
+//
+// type testing and converting
+//
+
+func (p *TCompactProtocol) isBoolType(b byte) bool {
+  return (b&0x0f) == COMPACT_BOOLEAN_TRUE || (b&0x0f) == COMPACT_BOOLEAN_FALSE
+}
+
+/**
+ * Given a TCompactType constant, convert it to its corresponding 
+ * TType value.
+ */
+func (p *TCompactProtocol) getTType(t TCompactType) (TType, os.Error) {
+  switch byte(t) & 0x0f {
+  case STOP:
+    return STOP, nil
+  case COMPACT_BOOLEAN_FALSE:
+  case COMPACT_BOOLEAN_TRUE:
+    return BOOL, nil
+  case COMPACT_BYTE:
+    return BYTE, nil
+  case COMPACT_I16:
+    return I16, nil
+  case COMPACT_I32:
+    return I32, nil
+  case COMPACT_I64:
+    return I64, nil
+  case COMPACT_DOUBLE:
+    return DOUBLE, nil
+  case COMPACT_BINARY:
+    return STRING, nil
+  case COMPACT_LIST:
+    return LIST, nil
+  case COMPACT_SET:
+    return SET, nil
+  case COMPACT_MAP:
+    return MAP, nil
+  case COMPACT_STRUCT:
+    return STRUCT, nil
+  }
+  return STOP, NewTException("don't know what type: " + string(t&0x0f))
+}
+
+/**
+ * Given a TType value, find the appropriate TCompactProtocol.Types constant.
+ */
+func (p *TCompactProtocol) getCompactType(t TType) TCompactType {
+  return _TTypeToCompactType[int(t)]
+}
diff --git a/lib/go/thrift/tcompact_protocol_test.go b/lib/go/thrift/tcompact_protocol_test.go
new file mode 100644
index 0000000..da0e39c
--- /dev/null
+++ b/lib/go/thrift/tcompact_protocol_test.go
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package thrift_test
+
+import (
+  . "thrift"
+  "testing"
+  //"bytes";
+)
+
+func TestReadWriteCompactProtocol(t *testing.T) {
+  ReadWriteProtocolTest(t, NewTCompactProtocolFactory())
+  /*
+     transports := []TTransport{
+       NewTMemoryBuffer(), 
+       NewTIOStreamTransportRW(bytes.NewBuffer(make([]byte, 0, 16384))),
+       NewTFramedTransport(NewTMemoryBuffer()),
+     }
+     for _, trans := range transports {
+       p := NewTCompactProtocol(trans);
+       ReadWriteBool(t, p, trans);
+       p = NewTCompactProtocol(trans);
+       ReadWriteByte(t, p, trans);
+       p = NewTCompactProtocol(trans);
+       ReadWriteI16(t, p, trans);
+       p = NewTCompactProtocol(trans);
+       ReadWriteI32(t, p, trans);
+       p = NewTCompactProtocol(trans);
+       ReadWriteI64(t, p, trans);
+       p = NewTCompactProtocol(trans);
+       ReadWriteDouble(t, p, trans);
+       p = NewTCompactProtocol(trans);
+       ReadWriteString(t, p, trans);
+       p = NewTCompactProtocol(trans);
+       ReadWriteBinary(t, p, trans);
+       trans.Close();
+     }
+  */
+}
diff --git a/lib/go/thrift/tcompare.go b/lib/go/thrift/tcompare.go
new file mode 100644
index 0000000..01fef44
--- /dev/null
+++ b/lib/go/thrift/tcompare.go
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+
+package thrift
+
+func CompareInt(i, j int) int {
+  if i > j {
+    return 1
+  }
+  if i < j {
+    return -1
+  }
+  return 0
+}
+
+func CompareInt16(i, j int16) int {
+  if i > j {
+    return 1
+  }
+  if i < j {
+    return -1
+  }
+  return 0
+}
+
+func CompareInt32(i, j int32) int {
+  if i > j {
+    return 1
+  }
+  if i < j {
+    return -1
+  }
+  return 0
+}
+
+func CompareInt64(i, j int32) int {
+  if i > j {
+    return 1
+  }
+  if i < j {
+    return -1
+  }
+  return 0
+}
+
+func CompareStringArray(i, j []string) int {
+  if cmp := CompareInt(len(i), len(j)); cmp != 0 {
+    return cmp
+  }
+  size := len(i)
+  for k := 0; k < size; k++ {
+    if cmp := CompareString(i[k], j[k]); cmp != 0 {
+      return cmp
+    }
+  }
+  return 0
+}
+
+func CompareString(i, j string) int {
+  if i > j {
+    return 1
+  }
+  if i < j {
+    return -1
+  }
+  return 0
+}
+
+func CompareFloat(i, j float32) int {
+  if i > j {
+    return 1
+  }
+  if i < j {
+    return -1
+  }
+  return 0
+}
+
+func CompareDouble(i, j float64) int {
+  if i > j {
+    return 1
+  }
+  if i < j {
+    return -1
+  }
+  return 0
+}
+
+func CompareByte(i, j byte) int {
+  if i > j {
+    return 1
+  }
+  if i < j {
+    return -1
+  }
+  return 0
+}
+
+func CompareBool(i, j bool) int {
+  if i {
+    if j {
+      return 0
+    }
+    return 1
+  }
+  if j {
+    return -1
+  }
+  return 0
+}
diff --git a/lib/go/thrift/tcontainer.go b/lib/go/thrift/tcontainer.go
new file mode 100644
index 0000000..9ea3cba
--- /dev/null
+++ b/lib/go/thrift/tcontainer.go
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+
+package thrift
+
+type TContainer interface {
+  Len() int
+  Contains(data interface{}) bool
+  Equals(other interface{}) bool
+  CompareTo(other interface{}) (int, bool)
+}
diff --git a/lib/go/thrift/texception.go b/lib/go/thrift/texception.go
new file mode 100644
index 0000000..be6cbd5
--- /dev/null
+++ b/lib/go/thrift/texception.go
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "os"
+)
+
+/**
+ * Generic exception class for Thrift.
+ *
+ */
+
+type TException interface {
+  String() string
+}
+
+type tException struct {
+  message string
+}
+
+func (p *tException) String() string {
+  return p.message
+}
+
+func NewTException(m string) TException {
+  return &tException{message: m}
+}
+
+func NewTExceptionFromOsError(e os.Error) TException {
+  if e == nil {
+    return nil
+  }
+  t, ok := e.(TException)
+  if ok {
+    return t
+  }
+  return NewTException(e.String())
+}
diff --git a/lib/go/thrift/texception_test.go b/lib/go/thrift/texception_test.go
new file mode 100644
index 0000000..50b3cdd
--- /dev/null
+++ b/lib/go/thrift/texception_test.go
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+package thrift_test
+
+import (
+  . "thrift"
+  "os"
+  "testing"
+)
+
+
+func TestTException(t *testing.T) {
+  exc := NewTException("")
+  if exc.String() != "" {
+    t.Fatalf("Expected empty string for exception but found '%s'", exc.String())
+  }
+  exc = NewTExceptionFromOsError(os.EOF)
+  if exc.String() != os.EOF.String() {
+    t.Fatalf("Expected '%s', but found '%s'", os.EOF.String(), exc.String())
+  }
+}
diff --git a/lib/go/thrift/tfield.go b/lib/go/thrift/tfield.go
new file mode 100644
index 0000000..31d9b89
--- /dev/null
+++ b/lib/go/thrift/tfield.go
@@ -0,0 +1,281 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "sort"
+)
+
+/**
+ * Helper class that encapsulates field metadata.
+ *
+ */
+type TField interface {
+  Name() string
+  TypeId() TType
+  Id() int
+  String() string
+  CompareTo(other interface{}) (int, bool)
+  Equals(other interface{}) bool
+}
+
+type tField struct {
+  name   string
+  typeId TType
+  id     int
+}
+
+func NewTFieldDefault() TField {
+  return ANONYMOUS_FIELD
+}
+
+func NewTField(n string, t TType, i int) TField {
+  return &tField{name: n, typeId: t, id: i}
+}
+
+func (p *tField) Name() string {
+  if p == nil {
+    return ""
+  }
+  return p.name
+}
+
+func (p *tField) TypeId() TType {
+  if p == nil {
+    return TType(VOID)
+  }
+  return p.typeId
+}
+
+func (p *tField) Id() int {
+  if p == nil {
+    return -1
+  }
+  return p.id
+}
+
+func (p *tField) String() string {
+  if p == nil {
+    return "<nil>"
+  }
+  return "<TField name:'" + p.name + "' type:" + string(p.typeId) + " field-id:" + string(p.id) + ">"
+}
+
+func (p *tField) CompareTo(other interface{}) (int, bool) {
+  if other == nil {
+    return 1, true
+  }
+  if data, ok := other.(TField); ok {
+    if p.Id() != data.Id() {
+      return CompareInt(p.Id(), data.Id()), true
+    }
+    if p.TypeId() != data.TypeId() {
+      return CompareByte(byte(p.TypeId()), byte(data.TypeId())), true
+    }
+    return CompareString(p.Name(), data.Name()), true
+  }
+  return 0, false
+}
+
+func (p *tField) Equals(other interface{}) bool {
+  if p == nil {
+    return other == nil
+  }
+  if other == nil {
+    return false
+  }
+  if data, ok := other.(TField); ok {
+    return p.TypeId() == data.TypeId() && p.Id() == data.Id()
+  }
+  return false
+}
+
+var ANONYMOUS_FIELD TField
+
+type tFieldArray []TField
+
+func (p tFieldArray) Len() int {
+  return len(p)
+}
+
+func (p tFieldArray) Less(i, j int) bool {
+  return p[i].Id() < p[j].Id()
+}
+
+func (p tFieldArray) Swap(i, j int) {
+  p[i], p[j] = p[j], p[i]
+}
+
+type TFieldContainer interface {
+  TContainer
+  FieldNameFromFieldId(id int) string
+  FieldIdFromFieldName(name string) int
+  FieldFromFieldId(id int) TField
+  FieldFromFieldName(name string) TField
+  At(i int) TField
+  Iter() <-chan TField
+}
+
+type tFieldContainer struct {
+  fields         []TField
+  nameToFieldMap map[string]TField
+  idToFieldMap   map[int]TField
+}
+
+func NewTFieldContainer(fields []TField) TFieldContainer {
+  sortedFields := make([]TField, len(fields))
+  nameToFieldMap := make(map[string]TField)
+  idToFieldMap := make(map[int]TField)
+  for i, field := range fields {
+    sortedFields[i] = field
+    idToFieldMap[field.Id()] = field
+    if field.Name() != "" {
+      nameToFieldMap[field.Name()] = field
+    }
+  }
+  sort.Sort(tFieldArray(sortedFields))
+  return &tFieldContainer{
+    fields:         fields,
+    nameToFieldMap: nameToFieldMap,
+    idToFieldMap:   idToFieldMap,
+  }
+}
+
+func (p *tFieldContainer) FieldNameFromFieldId(id int) string {
+  if field, ok := p.idToFieldMap[id]; ok {
+    return field.Name()
+  }
+  return ""
+}
+
+func (p *tFieldContainer) FieldIdFromFieldName(name string) int {
+  if field, ok := p.nameToFieldMap[name]; ok {
+    return field.Id()
+  }
+  return -1
+}
+
+func (p *tFieldContainer) FieldFromFieldId(id int) TField {
+  if field, ok := p.idToFieldMap[id]; ok {
+    return field
+  }
+  return ANONYMOUS_FIELD
+}
+
+func (p *tFieldContainer) FieldFromFieldName(name string) TField {
+  if field, ok := p.nameToFieldMap[name]; ok {
+    return field
+  }
+  return ANONYMOUS_FIELD
+}
+
+func (p *tFieldContainer) Len() int {
+  return len(p.fields)
+}
+
+func (p *tFieldContainer) At(i int) TField {
+  return p.FieldFromFieldId(i)
+}
+
+func (p *tFieldContainer) Contains(data interface{}) bool {
+  if i, ok := data.(int); ok {
+    for _, field := range p.fields {
+      if field.Id() == i {
+        return true
+      }
+    }
+  } else if i, ok := data.(int16); ok {
+    for _, field := range p.fields {
+      if field.Id() == int(i) {
+        return true
+      }
+    }
+  } else if s, ok := data.(string); ok {
+    for _, field := range p.fields {
+      if field.Name() == s {
+        return true
+      }
+    }
+  } else if f, ok := data.(TField); ok {
+    for _, field := range p.fields {
+      if field.Equals(f) {
+        return true
+      }
+    }
+  }
+  return false
+}
+
+func (p *tFieldContainer) Equals(other interface{}) bool {
+  if other == nil {
+    return false
+  }
+  if data, ok := other.(TFieldContainer); ok {
+    if p.Len() != data.Len() {
+      return false
+    }
+    for _, field := range p.fields {
+      if !data.Contains(field) {
+        return false
+      }
+    }
+    return true
+  }
+  return false
+}
+
+func (p *tFieldContainer) CompareTo(other interface{}) (int, bool) {
+  if other == nil {
+    return 1, true
+  }
+  if data, ok := other.(TFieldContainer); ok {
+    cont, ok2 := data.(*tFieldContainer)
+    if ok2 && p == cont {
+      return 0, true
+    }
+    if cmp := CompareInt(p.Len(), data.Len()); cmp != 0 {
+      return cmp, true
+    }
+    for _, field := range p.fields {
+      if cmp, ok3 := field.CompareTo(data.At(field.Id())); !ok3 || cmp != 0 {
+        return cmp, ok3
+      }
+    }
+    return 0, true
+  }
+  return 0, false
+}
+
+func (p *tFieldContainer) Iter() <-chan TField {
+  c := make(chan TField)
+  go p.iterate(c)
+  return c
+}
+
+func (p *tFieldContainer) iterate(c chan<- TField) {
+  for _, v := range p.fields {
+    c <- v
+  }
+  close(c)
+}
+
+func init() {
+  ANONYMOUS_FIELD = NewTField("", STOP, 0)
+}
diff --git a/lib/go/thrift/tframed_transport.go b/lib/go/thrift/tframed_transport.go
new file mode 100644
index 0000000..52049cb
--- /dev/null
+++ b/lib/go/thrift/tframed_transport.go
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "encoding/binary"
+  "bytes"
+  "os"
+)
+
+
+type TFramedTransport struct {
+  transport   TTransport
+  writeBuffer *bytes.Buffer
+  readBuffer  *bytes.Buffer
+}
+
+type tFramedTransportFactory struct {
+  factory TTransportFactory
+}
+
+func NewTFramedTransportFactory(factory TTransportFactory) TTransportFactory {
+  return &tFramedTransportFactory{factory: factory}
+}
+
+func (p *tFramedTransportFactory) GetTransport(base TTransport) TTransport {
+  return NewTFramedTransport(p.factory.GetTransport(base))
+}
+
+func NewTFramedTransport(transport TTransport) *TFramedTransport {
+  writeBuf := make([]byte, 0, 1024)
+  readBuf := make([]byte, 0, 1024)
+  return &TFramedTransport{transport: transport, writeBuffer: bytes.NewBuffer(writeBuf), readBuffer: bytes.NewBuffer(readBuf)}
+}
+
+func (p *TFramedTransport) Open() os.Error {
+  return p.transport.Open()
+}
+
+func (p *TFramedTransport) IsOpen() bool {
+  return p.transport.IsOpen()
+}
+
+func (p *TFramedTransport) Peek() bool {
+  return p.transport.Peek()
+}
+
+func (p *TFramedTransport) Close() os.Error {
+  return p.transport.Close()
+}
+
+func (p *TFramedTransport) Read(buf []byte) (int, os.Error) {
+  if p.readBuffer.Len() > 0 {
+    got, err := p.readBuffer.Read(buf)
+    if got > 0 {
+      return got, NewTTransportExceptionFromOsError(err)
+    }
+  }
+
+  // Read another frame of data
+  p.readFrame()
+
+  got, err := p.readBuffer.Read(buf)
+  return got, NewTTransportExceptionFromOsError(err)
+}
+
+func (p *TFramedTransport) ReadAll(buf []byte) (int, os.Error) {
+  return ReadAllTransport(p, buf)
+}
+
+func (p *TFramedTransport) Write(buf []byte) (int, os.Error) {
+  n, err := p.writeBuffer.Write(buf)
+  return n, NewTTransportExceptionFromOsError(err)
+}
+
+func (p *TFramedTransport) Flush() os.Error {
+  size := p.writeBuffer.Len()
+  buf := []byte{0, 0, 0, 0}
+  binary.BigEndian.PutUint32(buf, uint32(size))
+  _, err := p.transport.Write(buf)
+  if err != nil {
+    return NewTTransportExceptionFromOsError(err)
+  }
+  if size > 0 {
+    n, err := p.writeBuffer.WriteTo(p.transport)
+    if err != nil {
+      print("Error while flushing write buffer of size ", size, " to transport, only wrote ", n, " bytes: ", err.String(), "\n")
+      return NewTTransportExceptionFromOsError(err)
+    }
+  }
+  err = p.transport.Flush()
+  return NewTTransportExceptionFromOsError(err)
+}
+
+func (p *TFramedTransport) readFrame() (int, os.Error) {
+  buf := []byte{0, 0, 0, 0}
+  _, err := p.transport.ReadAll(buf)
+  if err != nil {
+    return 0, err
+  }
+  size := int(binary.BigEndian.Uint32(buf))
+  if size < 0 {
+    // TODO(pomack) log error
+    return 0, NewTTransportException(UNKNOWN_TRANSPORT_EXCEPTION, "Read a negative frame size ("+string(size)+")")
+  }
+  if size == 0 {
+    return 0, nil
+  }
+  buf2 := make([]byte, size)
+  n, err := p.transport.ReadAll(buf2)
+  if err != nil {
+    return n, err
+  }
+  p.readBuffer = bytes.NewBuffer(buf2)
+  return size, nil
+}
diff --git a/lib/go/thrift/tframed_transport_test.go b/lib/go/thrift/tframed_transport_test.go
new file mode 100644
index 0000000..566318c
--- /dev/null
+++ b/lib/go/thrift/tframed_transport_test.go
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package thrift_test
+
+import (
+  . "thrift"
+  "testing"
+)
+
+func TestFramedTransport(t *testing.T) {
+  trans := NewTFramedTransport(NewTMemoryBuffer())
+  TransportTest(t, trans, trans)
+}
diff --git a/lib/go/thrift/thttp_client.go b/lib/go/thrift/thttp_client.go
new file mode 100644
index 0000000..e09ecdf
--- /dev/null
+++ b/lib/go/thrift/thttp_client.go
@@ -0,0 +1,146 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "bytes"
+  "http"
+  "os"
+)
+
+
+type THttpClient struct {
+  response           *http.Response
+  url                *http.URL
+  requestBuffer      *bytes.Buffer
+  nsecConnectTimeout int64
+  nsecReadTimeout    int64
+}
+
+type THttpClientTransportFactory struct {
+  url    string
+  isPost bool
+}
+
+func (p *THttpClientTransportFactory) GetTransport(trans TTransport) TTransport {
+  if trans != nil {
+    t, ok := trans.(*THttpClient)
+    if ok && t.url != nil {
+      if t.requestBuffer != nil {
+        t2, _ := NewTHttpPostClient(t.url.String())
+        return t2
+      }
+      t2, _ := NewTHttpClient(t.url.String())
+      return t2
+    }
+  }
+  if p.isPost {
+    s, _ := NewTHttpPostClient(p.url)
+    return s
+  }
+  s, _ := NewTHttpClient(p.url)
+  return s
+}
+
+func NewTHttpClientTransportFactory(url string) *THttpClientTransportFactory {
+  return &THttpClientTransportFactory{url: url, isPost: false}
+}
+
+func NewTHttpPostClientTransportFactory(url string) *THttpClientTransportFactory {
+  return &THttpClientTransportFactory{url: url, isPost: true}
+}
+
+
+func NewTHttpClient(url string) (TTransport, os.Error) {
+  response, finalUrl, err := http.Get(url)
+  if err != nil {
+    return nil, err
+  }
+  parsedURL, err := http.ParseURL(finalUrl)
+  if err != nil {
+    return nil, err
+  }
+  return &THttpClient{response: response, url: parsedURL}, nil
+}
+
+func NewTHttpPostClient(url string) (TTransport, os.Error) {
+  parsedURL, err := http.ParseURL(url)
+  if err != nil {
+    return nil, err
+  }
+  buf := make([]byte, 0, 1024)
+  return &THttpClient{url: parsedURL, requestBuffer: bytes.NewBuffer(buf)}, nil
+}
+
+func (p *THttpClient) Open() os.Error {
+  // do nothing
+  return nil
+}
+
+func (p *THttpClient) IsOpen() bool {
+  return p.response != nil || p.requestBuffer != nil
+}
+
+func (p *THttpClient) Peek() bool {
+  return p.IsOpen()
+}
+
+func (p *THttpClient) Close() os.Error {
+  if p.response != nil && p.response.Body != nil {
+    err := p.response.Body.Close()
+    p.response = nil
+    return err
+  }
+  if p.requestBuffer != nil {
+    p.requestBuffer.Reset()
+    p.requestBuffer = nil
+  }
+  return nil
+}
+
+func (p *THttpClient) Read(buf []byte) (int, os.Error) {
+  if p.response == nil {
+    return 0, NewTTransportException(NOT_OPEN, "Response buffer is empty, no request.")
+  }
+  n, err := p.response.Body.Read(buf)
+  return n, NewTTransportExceptionFromOsError(err)
+}
+
+func (p *THttpClient) ReadAll(buf []byte) (int, os.Error) {
+  return ReadAllTransport(p, buf)
+}
+
+func (p *THttpClient) Write(buf []byte) (int, os.Error) {
+  n, err := p.requestBuffer.Write(buf)
+  return n, err
+}
+
+func (p *THttpClient) Flush() os.Error {
+  response, err := http.Post(p.url.String(), "application/x-thrift", p.requestBuffer)
+  if err != nil {
+    return NewTTransportExceptionFromOsError(err)
+  }
+  if response.StatusCode != http.StatusOK {
+    // TODO(pomack) log bad response
+    return NewTTransportException(UNKNOWN_TRANSPORT_EXCEPTION, "HTTP Response code: "+string(response.StatusCode))
+  }
+  p.response = response
+  return nil
+}
diff --git a/lib/go/thrift/thttp_client_test.go b/lib/go/thrift/thttp_client_test.go
new file mode 100644
index 0000000..1af8cd3
--- /dev/null
+++ b/lib/go/thrift/thttp_client_test.go
@@ -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.
+ */
+
+package thrift_test
+
+import (
+  . "thrift"
+  "testing"
+  "http"
+  "net"
+)
+
+func TestHttpClient(t *testing.T) {
+  addr, err := FindAvailableTCPServerPort(40000)
+  if err != nil {
+    t.Fatalf("Unable to find available tcp port addr: %s", err)
+  }
+  l, err := net.Listen(addr.Network(), addr.String())
+  if err != nil {
+    t.Fatalf("Unable to setup tcp listener on %s: %s", addr.String(), err)
+  }
+  go http.Serve(l, &HTTPEchoServer{})
+  trans, err := NewTHttpPostClient("http://" + addr.String())
+  if err != nil {
+    l.Close()
+    t.Fatalf("Unable to connect to %s: %s", addr.String(), err)
+  }
+  TransportTest(t, trans, trans)
+}
diff --git a/lib/go/thrift/tiostream_transport.go b/lib/go/thrift/tiostream_transport.go
new file mode 100644
index 0000000..5c4beea
--- /dev/null
+++ b/lib/go/thrift/tiostream_transport.go
@@ -0,0 +1,231 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "bufio"
+  "io"
+  "os"
+)
+
+/**
+ * This is the most commonly used base transport. It takes an InputStream
+ * and an OutputStream and uses those to perform all transport operations.
+ * This allows for compatibility with all the nice constructs Java already
+ * has to provide a variety of types of streams.
+ *
+ */
+type TIOStreamTransport struct {
+  Reader       io.Reader
+  Writer       io.Writer
+  IsReadWriter bool
+}
+
+type TIOStreamTransportFactory struct {
+  Reader       io.Reader
+  Writer       io.Writer
+  IsReadWriter bool
+}
+
+func (p *TIOStreamTransportFactory) GetTransport(trans TTransport) TTransport {
+  if trans != nil {
+    t, ok := trans.(*TIOStreamTransport)
+    if ok {
+      if t.IsReadWriter {
+        return NewTIOStreamTransportRW(t.Reader.(io.ReadWriter))
+      }
+      if t.Reader != nil && t.Writer != nil {
+        return NewTIOStreamTransportRAndW(t.Reader, t.Writer)
+      }
+      if t.Reader != nil && t.Writer == nil {
+        return NewTIOStreamTransportR(t.Reader)
+      }
+      if t.Reader == nil && t.Writer != nil {
+        return NewTIOStreamTransportW(t.Writer)
+      }
+      return NewTIOStreamTransportDefault()
+    }
+  }
+  if p.IsReadWriter {
+    return NewTIOStreamTransportRW(p.Reader.(io.ReadWriter))
+  }
+  if p.Reader != nil && p.Writer != nil {
+    return NewTIOStreamTransportRAndW(p.Reader, p.Writer)
+  }
+  if p.Reader != nil && p.Writer == nil {
+    return NewTIOStreamTransportR(p.Reader)
+  }
+  if p.Reader == nil && p.Writer != nil {
+    return NewTIOStreamTransportW(p.Writer)
+  }
+  return NewTIOStreamTransportDefault()
+}
+
+func NewTIOStreamTransportFactory(reader io.Reader, writer io.Writer, isReadWriter bool) *TIOStreamTransportFactory {
+  return &TIOStreamTransportFactory{Reader: reader, Writer: writer, IsReadWriter: isReadWriter}
+}
+
+
+/**
+ * Subclasses can invoke the default constructor and then assign the input
+ * streams in the open method.
+ */
+func NewTIOStreamTransportDefault() *TIOStreamTransport {
+  return &TIOStreamTransport{}
+}
+
+/**
+ * Input stream constructor.
+ *
+ * @param is Input stream to read from
+ */
+func NewTIOStreamTransportR(r io.Reader) *TIOStreamTransport {
+  return &TIOStreamTransport{Reader: bufio.NewReader(r)}
+}
+
+/**
+ * Output stream constructor.
+ *
+ * @param os Output stream to read from
+ */
+func NewTIOStreamTransportW(w io.Writer) *TIOStreamTransport {
+  return &TIOStreamTransport{Writer: bufio.NewWriter(w)}
+}
+
+/**
+ * Two-way stream constructor.
+ *
+ * @param is Input stream to read from
+ * @param os Output stream to read from
+ */
+func NewTIOStreamTransportRAndW(r io.Reader, w io.Writer) *TIOStreamTransport {
+  return &TIOStreamTransport{Reader: bufio.NewReader(r), Writer: bufio.NewWriter(w)}
+}
+
+/**
+ * Two-way stream constructor.
+ *
+ * @param is Input stream to read from
+ * @param os Output stream to read from
+ */
+func NewTIOStreamTransportRW(rw io.ReadWriter) *TIOStreamTransport {
+  // bufio has a bug where once a Reader hits EOF, a new Write never brings the reader out of EOF
+  // even if reader and writer use the same underlier
+  //bufrw := bufio.NewReadWriter(bufio.NewReader(rw), bufio.NewWriter(rw));
+  return &TIOStreamTransport{Reader: rw, Writer: rw, IsReadWriter: true}
+}
+
+/**
+ * The streams must already be open at construction time, so this should
+ * always return true.
+ *
+ * @return true
+ */
+func (p *TIOStreamTransport) IsOpen() bool {
+  return true
+}
+
+/**
+ * The streams must already be open. This method does nothing.
+ */
+func (p *TIOStreamTransport) Open() os.Error {
+  return nil
+}
+
+func (p *TIOStreamTransport) Peek() bool {
+  return p.IsOpen()
+}
+
+/**
+ * Closes both the input and output streams.
+ */
+func (p *TIOStreamTransport) Close() os.Error {
+  closedReader := false
+  if p.Reader != nil {
+    c, ok := p.Reader.(io.Closer)
+    if ok {
+      e := c.Close()
+      closedReader = true
+      if e != nil {
+        LOGGER.Print("Error closing input stream.", e)
+      }
+    }
+    p.Reader = nil
+  }
+  if p.Writer != nil && (!closedReader || !p.IsReadWriter) {
+    c, ok := p.Writer.(io.Closer)
+    if ok {
+      e := c.Close()
+      if e != nil {
+        LOGGER.Print("Error closing output stream.", e)
+      }
+    }
+    p.Writer = nil
+  }
+  return nil
+}
+
+/**
+ * Reads from the underlying input stream if not null.
+ */
+func (p *TIOStreamTransport) Read(buf []byte) (int, os.Error) {
+  if p.Reader == nil {
+    return 0, NewTTransportException(NOT_OPEN, "Cannot read from null inputStream")
+  }
+  n, err := p.Reader.Read(buf)
+  return n, NewTTransportExceptionFromOsError(err)
+}
+
+func (p *TIOStreamTransport) ReadAll(buf []byte) (int, os.Error) {
+  return ReadAllTransport(p, buf)
+}
+
+
+/**
+ * Writes to the underlying output stream if not null.
+ */
+func (p *TIOStreamTransport) Write(buf []byte) (int, os.Error) {
+  if p.Writer == nil {
+    LOGGER.Print("Could not write to iostream as Writer is null\n")
+    return 0, NewTTransportException(NOT_OPEN, "Cannot write to null outputStream")
+  }
+  n, err := p.Writer.Write(buf)
+  if n == 0 || err != nil {
+    LOGGER.Print("Error writing to iostream, only wrote ", n, " bytes: ", err.String(), "\n")
+  }
+  return n, NewTTransportExceptionFromOsError(err)
+}
+
+/**
+ * Flushes the underlying output stream if not null.
+ */
+func (p *TIOStreamTransport) Flush() os.Error {
+  if p.Writer == nil {
+    return NewTTransportException(NOT_OPEN, "Cannot flush null outputStream")
+  }
+  f, ok := p.Writer.(Flusher)
+  if ok {
+    err := f.Flush()
+    if err != nil {
+      return NewTTransportExceptionFromOsError(err)
+    }
+  }
+  return nil
+}
diff --git a/lib/go/thrift/tiostream_transport_test.go b/lib/go/thrift/tiostream_transport_test.go
new file mode 100644
index 0000000..a7425c7
--- /dev/null
+++ b/lib/go/thrift/tiostream_transport_test.go
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package thrift_test
+
+import (
+  . "thrift"
+  "testing"
+  "bytes"
+)
+
+func TestIOStreamTransport(t *testing.T) {
+  trans := NewTIOStreamTransportRW(bytes.NewBuffer(make([]byte, 0, 1024)))
+  TransportTest(t, trans, trans)
+}
diff --git a/lib/go/thrift/tjson_protocol.go b/lib/go/thrift/tjson_protocol.go
new file mode 100644
index 0000000..45ab700
--- /dev/null
+++ b/lib/go/thrift/tjson_protocol.go
@@ -0,0 +1,537 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "encoding/base64"
+  "fmt"
+)
+
+const (
+  THRIFT_JSON_PROTOCOL_VERSION = 1
+)
+
+// for references to _ParseContext see tsimplejson_protocol.go
+
+/**
+ * JSON protocol implementation for thrift.
+ *
+ * This protocol produces/consumes a simple output format
+ * suitable for parsing by scripting languages.  It should not be
+ * confused with the full-featured TJSONProtocol.
+ *
+ */
+type TJSONProtocol struct {
+  *TSimpleJSONProtocol
+}
+
+/**
+ * Constructor
+ */
+func NewTJSONProtocol(t TTransport) *TJSONProtocol {
+  v := &TJSONProtocol{TSimpleJSONProtocol: NewTSimpleJSONProtocol(t)}
+  v.parseContextStack.Push(int(_CONTEXT_IN_TOPLEVEL))
+  v.dumpContext.Push(int(_CONTEXT_IN_TOPLEVEL))
+  return v
+}
+
+/**
+ * Factory
+ */
+type TJSONProtocolFactory struct{}
+
+func (p *TJSONProtocolFactory) GetProtocol(trans TTransport) TProtocol {
+  return NewTJSONProtocol(trans)
+}
+
+func NewTJSONProtocolFactory() *TJSONProtocolFactory {
+  return &TJSONProtocolFactory{}
+}
+
+
+func (p *TJSONProtocol) WriteMessageBegin(name string, typeId TMessageType, seqId int32) TProtocolException {
+  if e := p.OutputListBegin(); e != nil {
+    return e
+  }
+  if e := p.WriteI32(THRIFT_JSON_PROTOCOL_VERSION); e != nil {
+    return e
+  }
+  if e := p.WriteString(name); e != nil {
+    return e
+  }
+  if e := p.WriteByte(byte(typeId)); e != nil {
+    return e
+  }
+  if e := p.WriteI32(seqId); e != nil {
+    return e
+  }
+  return nil
+}
+
+func (p *TJSONProtocol) WriteMessageEnd() TProtocolException {
+  return p.OutputListEnd()
+}
+
+func (p *TJSONProtocol) WriteStructBegin(name string) TProtocolException {
+  if e := p.OutputObjectBegin(); e != nil {
+    return e
+  }
+  return nil
+}
+
+func (p *TJSONProtocol) WriteStructEnd() TProtocolException {
+  return p.OutputObjectEnd()
+}
+
+func (p *TJSONProtocol) WriteFieldBegin(name string, typeId TType, id int16) TProtocolException {
+  if e := p.WriteI16(id); e != nil {
+    return e
+  }
+  if e := p.OutputObjectBegin(); e != nil {
+    return e
+  }
+  if e := p.WriteString(p.TypeIdToString(typeId)); e != nil {
+    return e
+  }
+  return nil
+}
+
+func (p *TJSONProtocol) WriteFieldEnd() TProtocolException {
+  return p.OutputObjectEnd()
+}
+
+func (p *TJSONProtocol) WriteFieldStop() TProtocolException { return nil }
+
+func (p *TJSONProtocol) WriteMapBegin(keyType TType, valueType TType, size int) TProtocolException {
+  if e := p.OutputListBegin(); e != nil {
+    return e
+  }
+  if e := p.WriteString(p.TypeIdToString(keyType)); e != nil {
+    return e
+  }
+  if e := p.WriteString(p.TypeIdToString(valueType)); e != nil {
+    return e
+  }
+  return p.WriteI64(int64(size))
+}
+
+func (p *TJSONProtocol) WriteMapEnd() TProtocolException {
+  return p.OutputListEnd()
+}
+
+func (p *TJSONProtocol) WriteListBegin(elemType TType, size int) TProtocolException {
+  return p.OutputElemListBegin(elemType, size)
+}
+
+func (p *TJSONProtocol) WriteListEnd() TProtocolException {
+  return p.OutputListEnd()
+}
+
+func (p *TJSONProtocol) WriteSetBegin(elemType TType, size int) TProtocolException {
+  return p.OutputElemListBegin(elemType, size)
+}
+
+func (p *TJSONProtocol) WriteSetEnd() TProtocolException {
+  return p.OutputListEnd()
+}
+
+func (p *TJSONProtocol) WriteBool(b bool) TProtocolException {
+  return p.OutputBool(b)
+}
+
+func (p *TJSONProtocol) WriteByte(b byte) TProtocolException {
+  return p.WriteI32(int32(b))
+}
+
+func (p *TJSONProtocol) WriteI16(v int16) TProtocolException {
+  return p.WriteI32(int32(v))
+}
+
+func (p *TJSONProtocol) WriteI32(v int32) TProtocolException {
+  return p.OutputI64(int64(v))
+}
+
+func (p *TJSONProtocol) WriteI64(v int64) TProtocolException {
+  return p.OutputI64(int64(v))
+}
+
+func (p *TJSONProtocol) WriteDouble(v float64) TProtocolException {
+  return p.OutputF64(v)
+}
+
+func (p *TJSONProtocol) WriteString(v string) TProtocolException {
+  return p.OutputString(v)
+}
+
+func (p *TJSONProtocol) WriteBinary(v []byte) TProtocolException {
+  // JSON library only takes in a string, 
+  // not an arbitrary byte array, to ensure bytes are transmitted
+  // efficiently we must convert this into a valid JSON string
+  // therefore we use base64 encoding to avoid excessive escaping/quoting
+  if e := p.OutputPreValue(); e != nil {
+    return e
+  }
+  p.writer.Write(JSON_QUOTE_BYTES)
+  writer := base64.NewEncoder(base64.StdEncoding, p.writer)
+  if _, e := writer.Write(v); e != nil {
+    return NewTProtocolExceptionFromOsError(e)
+  }
+  writer.Close()
+  p.writer.Write(JSON_QUOTE_BYTES)
+  return p.OutputPostValue()
+}
+
+/**
+ * Reading methods.
+ */
+
+func (p *TJSONProtocol) ReadMessageBegin() (name string, typeId TMessageType, seqId int32, err TProtocolException) {
+  if isNull, err := p.ParseListBegin(); isNull || err != nil {
+    return name, typeId, seqId, err
+  }
+  version, err := p.ReadI32()
+  if err != nil {
+    return name, typeId, seqId, err
+  }
+  if version != THRIFT_JSON_PROTOCOL_VERSION {
+    return name, typeId, seqId, NewTProtocolException(INVALID_DATA, fmt.Sprint("Unknown Protocol version ", version, ", expected version ", THRIFT_JSON_PROTOCOL_VERSION, "\n"))
+  }
+  if name, err = p.ReadString(); err != nil {
+    return name, typeId, seqId, err
+  }
+  bTypeId, err := p.ReadByte()
+  typeId = TMessageType(bTypeId)
+  if err != nil {
+    return name, typeId, seqId, err
+  }
+  if seqId, err = p.ReadI32(); err != nil {
+    return name, typeId, seqId, err
+  }
+  return name, typeId, seqId, nil
+}
+
+func (p *TJSONProtocol) ReadMessageEnd() TProtocolException {
+  err := p.ParseListEnd()
+  return err
+}
+
+func (p *TJSONProtocol) ReadStructBegin() (name string, err TProtocolException) {
+  _, err = p.ParseObjectStart()
+  return "", err
+}
+
+func (p *TJSONProtocol) ReadStructEnd() TProtocolException {
+  return p.ParseObjectEnd()
+}
+
+func (p *TJSONProtocol) ReadFieldBegin() (string, TType, int16, TProtocolException) {
+  if p.reader.Buffered() < 1 {
+    return "", STOP, -1, nil
+  }
+  b, _ := p.reader.Peek(1)
+  if len(b) < 1 || b[0] == JSON_RBRACE[0] || b[0] == JSON_RBRACKET[0] {
+    return "", STOP, -1, nil
+  }
+  fieldId, err := p.ReadI16()
+  if err != nil {
+    return "", STOP, fieldId, err
+  }
+  if _, err = p.ParseObjectStart(); err != nil {
+    return "", STOP, fieldId, err
+  }
+  sType, err := p.ReadString()
+  fType := p.StringToTypeId(sType)
+  return "", fType, fieldId, err
+}
+
+func (p *TJSONProtocol) ReadFieldEnd() TProtocolException {
+  return p.ParseObjectEnd()
+}
+
+func (p *TJSONProtocol) ReadMapBegin() (keyType TType, valueType TType, size int, e TProtocolException) {
+  if isNull, e := p.ParseListBegin(); isNull || e != nil {
+    return VOID, VOID, 0, e
+  }
+
+  // read keyType
+  sKeyType, e := p.ReadString()
+  keyType = p.StringToTypeId(sKeyType)
+  if e != nil {
+    return keyType, valueType, size, e
+  }
+
+  // read valueType
+  sValueType, e := p.ReadString()
+  valueType = p.StringToTypeId(sValueType)
+  if e != nil {
+    return keyType, valueType, size, e
+  }
+
+  // read size
+  iSize, err := p.ReadI64()
+  size = int(iSize)
+  return keyType, valueType, size, err
+}
+
+func (p *TJSONProtocol) ReadMapEnd() TProtocolException {
+  return p.ParseListEnd()
+}
+
+func (p *TJSONProtocol) ReadListBegin() (elemType TType, size int, e TProtocolException) {
+  return p.ParseElemListBegin()
+}
+
+func (p *TJSONProtocol) ReadListEnd() TProtocolException {
+  return p.ParseListEnd()
+}
+
+func (p *TJSONProtocol) ReadSetBegin() (elemType TType, size int, e TProtocolException) {
+  return p.ParseElemListBegin()
+}
+
+func (p *TJSONProtocol) ReadSetEnd() TProtocolException {
+  return p.ParseListEnd()
+}
+
+func (p *TJSONProtocol) ReadBool() (bool, TProtocolException) {
+  var value bool
+  if err := p.ParsePreValue(); err != nil {
+    return value, err
+  }
+  b, _ := p.reader.Peek(len(JSON_FALSE))
+  if len(b) > 0 {
+    switch b[0] {
+    case JSON_TRUE[0]:
+      if string(b[0:len(JSON_TRUE)]) == string(JSON_TRUE) {
+        p.reader.Read(b[0:len(JSON_TRUE)])
+        value = true
+      } else {
+        return value, NewTProtocolException(INVALID_DATA, "Expected \"true\" but found: "+string(b))
+      }
+      break
+    case JSON_FALSE[0]:
+      if string(b[0:len(JSON_FALSE)]) == string(JSON_FALSE) {
+        p.reader.Read(b[0:len(JSON_FALSE)])
+        value = false
+      } else {
+        return value, NewTProtocolException(INVALID_DATA, "Expected \"false\" but found: "+string(b))
+      }
+      break
+    case JSON_NULL[0]:
+      if string(b[0:len(JSON_NULL)]) == string(JSON_NULL) {
+        p.reader.Read(b[0:len(JSON_NULL)])
+        value = false
+      } else {
+        return value, NewTProtocolException(INVALID_DATA, "Expected \"null\" but found: "+string(b))
+      }
+    default:
+      return value, NewTProtocolException(INVALID_DATA, "Expected \"true\", \"false\", or \"null\" but found: "+string(b))
+    }
+  }
+  return value, p.ParsePostValue()
+}
+
+func (p *TJSONProtocol) ReadByte() (byte, TProtocolException) {
+  v, err := p.ReadI64()
+  return byte(v), err
+}
+
+func (p *TJSONProtocol) ReadI16() (int16, TProtocolException) {
+  v, err := p.ReadI64()
+  return int16(v), err
+}
+
+func (p *TJSONProtocol) ReadI32() (int32, TProtocolException) {
+  v, err := p.ReadI64()
+  return int32(v), err
+}
+
+func (p *TJSONProtocol) ReadI64() (int64, TProtocolException) {
+  v, _, err := p.ParseI64()
+  return v, err
+}
+
+func (p *TJSONProtocol) ReadDouble() (float64, TProtocolException) {
+  v, _, err := p.ParseF64()
+  return v, err
+}
+
+func (p *TJSONProtocol) ReadString() (string, TProtocolException) {
+  var v string
+  if err := p.ParsePreValue(); err != nil {
+    return v, err
+  }
+  b, _ := p.reader.Peek(len(JSON_NULL))
+  if len(b) > 0 && b[0] == JSON_QUOTE {
+    p.reader.ReadByte()
+    value, err := p.ParseStringBody()
+    v = value
+    if err != nil {
+      return v, err
+    }
+  } else if len(b) >= len(JSON_NULL) && string(b[0:len(JSON_NULL)]) == string(JSON_NULL) {
+    _, err := p.reader.Read(b[0:len(JSON_NULL)])
+    if err != nil {
+      return v, NewTProtocolExceptionFromOsError(err)
+    }
+  } else {
+    return v, NewTProtocolException(INVALID_DATA, fmt.Sprint("Expected a JSON string, found ", string(b)))
+  }
+  return v, p.ParsePostValue()
+}
+
+func (p *TJSONProtocol) ReadBinary() ([]byte, TProtocolException) {
+  var v []byte
+  if err := p.ParsePreValue(); err != nil {
+    return nil, err
+  }
+  b, _ := p.reader.Peek(len(JSON_NULL))
+  if len(b) > 0 && b[0] == JSON_QUOTE {
+    p.reader.ReadByte()
+    value, err := p.ParseBase64EncodedBody()
+    v = value
+    if err != nil {
+      return v, err
+    }
+  } else if len(b) >= len(JSON_NULL) && string(b[0:len(JSON_NULL)]) == string(JSON_NULL) {
+    _, err := p.reader.Read(b[0:len(JSON_NULL)])
+    if err != nil {
+      return v, NewTProtocolExceptionFromOsError(err)
+    }
+  } else {
+    return v, NewTProtocolException(INVALID_DATA, fmt.Sprint("Expected a JSON string, found ", string(b)))
+  }
+  return v, p.ParsePostValue()
+}
+
+func (p *TJSONProtocol) Flush() (err TProtocolException) {
+  return NewTProtocolExceptionFromOsError(p.writer.Flush())
+}
+
+func (p *TJSONProtocol) Skip(fieldType TType) (err TProtocolException) {
+  return SkipDefaultDepth(p, fieldType)
+}
+
+func (p *TJSONProtocol) Transport() TTransport {
+  return p.trans
+}
+
+func (p *TJSONProtocol) readElemListBegin() (elemType TType, size int, e TProtocolException) {
+  if isNull, e := p.ParseListBegin(); isNull || e != nil {
+    return VOID, 0, e
+  }
+  sElemType, err := p.ReadString()
+  elemType = p.StringToTypeId(sElemType)
+  if err != nil {
+    return elemType, size, err
+  }
+  nSize, err2 := p.ReadI64()
+  size = int(nSize)
+  return elemType, size, err2
+}
+
+func (p *TJSONProtocol) writeElemListBegin(elemType TType, size int) TProtocolException {
+  if e := p.OutputListBegin(); e != nil {
+    return e
+  }
+  if e := p.OutputString(p.TypeIdToString(elemType)); e != nil {
+    return e
+  }
+  if e := p.OutputI64(int64(size)); e != nil {
+    return e
+  }
+  return nil
+}
+
+func (p *TJSONProtocol) TypeIdToString(fieldType TType) string {
+  switch byte(fieldType) {
+  case STOP:
+    return "stp"
+  case VOID:
+    return "v"
+  case BOOL:
+    return "tf"
+  case BYTE:
+    return "i8"
+  case DOUBLE:
+    return "dbl"
+  case I16:
+    return "i16"
+  case I32:
+    return "i32"
+  case I64:
+    return "i64"
+  case STRING:
+    return "str"
+  case STRUCT:
+    return "rec"
+  case MAP:
+    return "map"
+  case SET:
+    return "set"
+  case LIST:
+    return "lst"
+  case ENUM:
+    return "i32"
+  case UTF16:
+    return "str"
+  case GENERIC:
+    return "gen"
+  }
+  return ""
+}
+
+func (p *TJSONProtocol) StringToTypeId(fieldType string) TType {
+  switch fieldType {
+  case "stp":
+    return TType(STOP)
+  case "v":
+    return TType(VOID)
+  case "tf":
+    return TType(BOOL)
+  case "i8":
+    return TType(BYTE)
+  case "dbl":
+    return TType(DOUBLE)
+  case "16":
+    return TType(I16)
+  case "i32":
+    return TType(I32)
+  case "i64":
+    return TType(I64)
+  case "str":
+    return TType(STRING)
+  case "rec":
+    return TType(STRUCT)
+  case "map":
+    return TType(MAP)
+  case "set":
+    return TType(SET)
+  case "lst":
+    return TType(LIST)
+  case "enm":
+    return TType(ENUM)
+  case "u16":
+    return TType(UTF16)
+  case "gen":
+    return TType(GENERIC)
+  }
+  return TType(STOP)
+}
diff --git a/lib/go/thrift/tjson_protocol_test.go b/lib/go/thrift/tjson_protocol_test.go
new file mode 100644
index 0000000..60f0f2e
--- /dev/null
+++ b/lib/go/thrift/tjson_protocol_test.go
@@ -0,0 +1,674 @@
+/*
+ * 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.
+ */
+
+package thrift_test
+
+import (
+  . "thrift"
+  "encoding/base64"
+  "fmt"
+  "json"
+  "math"
+  "strconv"
+  "testing"
+)
+
+func TestWriteJSONProtocolBool(t *testing.T) {
+  thetype := "boolean"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  for _, value := range BOOL_VALUES {
+    if e := p.WriteBool(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if e := p.Flush(); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+    }
+    s := trans.String()
+    if s != fmt.Sprint(value) {
+      t.Fatalf("Bad value for %s %v: %s", thetype, value, s)
+    }
+    v := false
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestReadJSONProtocolBool(t *testing.T) {
+  thetype := "boolean"
+  for _, value := range BOOL_VALUES {
+    trans := NewTMemoryBuffer()
+    p := NewTJSONProtocol(trans)
+    if value {
+      trans.Write(JSON_TRUE)
+    } else {
+      trans.Write(JSON_FALSE)
+    }
+    trans.Flush()
+    s := trans.String()
+    v, e := p.ReadBool()
+    if e != nil {
+      t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if v != value {
+      t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+    }
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+    trans.Close()
+  }
+}
+
+func TestWriteJSONProtocolByte(t *testing.T) {
+  thetype := "byte"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  for _, value := range BYTE_VALUES {
+    if e := p.WriteByte(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if e := p.Flush(); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+    }
+    s := trans.String()
+    if s != fmt.Sprint(value) {
+      t.Fatalf("Bad value for %s %v: %s", thetype, value, s)
+    }
+    v := byte(0)
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestReadJSONProtocolByte(t *testing.T) {
+  thetype := "byte"
+  for _, value := range BYTE_VALUES {
+    trans := NewTMemoryBuffer()
+    p := NewTJSONProtocol(trans)
+    trans.WriteString(strconv.Itoa(int(value)))
+    trans.Flush()
+    s := trans.String()
+    v, e := p.ReadByte()
+    if e != nil {
+      t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if v != value {
+      t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+    }
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+    trans.Close()
+  }
+}
+
+func TestWriteJSONProtocolI16(t *testing.T) {
+  thetype := "int16"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  for _, value := range INT16_VALUES {
+    if e := p.WriteI16(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if e := p.Flush(); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+    }
+    s := trans.String()
+    if s != fmt.Sprint(value) {
+      t.Fatalf("Bad value for %s %v: %s", thetype, value, s)
+    }
+    v := int16(0)
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestReadJSONProtocolI16(t *testing.T) {
+  thetype := "int16"
+  for _, value := range INT16_VALUES {
+    trans := NewTMemoryBuffer()
+    p := NewTJSONProtocol(trans)
+    trans.WriteString(strconv.Itoa(int(value)))
+    trans.Flush()
+    s := trans.String()
+    v, e := p.ReadI16()
+    if e != nil {
+      t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if v != value {
+      t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+    }
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+    trans.Close()
+  }
+}
+
+func TestWriteJSONProtocolI32(t *testing.T) {
+  thetype := "int32"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  for _, value := range INT32_VALUES {
+    if e := p.WriteI32(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if e := p.Flush(); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+    }
+    s := trans.String()
+    if s != fmt.Sprint(value) {
+      t.Fatalf("Bad value for %s %v: %s", thetype, value, s)
+    }
+    v := int32(0)
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestReadJSONProtocolI32(t *testing.T) {
+  thetype := "int32"
+  for _, value := range INT32_VALUES {
+    trans := NewTMemoryBuffer()
+    p := NewTJSONProtocol(trans)
+    trans.WriteString(strconv.Itoa(int(value)))
+    trans.Flush()
+    s := trans.String()
+    v, e := p.ReadI32()
+    if e != nil {
+      t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if v != value {
+      t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+    }
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+    trans.Close()
+  }
+}
+
+func TestWriteJSONProtocolI64(t *testing.T) {
+  thetype := "int64"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  for _, value := range INT64_VALUES {
+    if e := p.WriteI64(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if e := p.Flush(); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+    }
+    s := trans.String()
+    if s != fmt.Sprint(value) {
+      t.Fatalf("Bad value for %s %v: %s", thetype, value, s)
+    }
+    v := int64(0)
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestReadJSONProtocolI64(t *testing.T) {
+  thetype := "int64"
+  for _, value := range INT64_VALUES {
+    trans := NewTMemoryBuffer()
+    p := NewTJSONProtocol(trans)
+    trans.WriteString(strconv.Itoa64(value))
+    trans.Flush()
+    s := trans.String()
+    v, e := p.ReadI64()
+    if e != nil {
+      t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if v != value {
+      t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+    }
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+    trans.Close()
+  }
+}
+
+func TestWriteJSONProtocolDouble(t *testing.T) {
+  thetype := "double"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  for _, value := range DOUBLE_VALUES {
+    if e := p.WriteDouble(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if e := p.Flush(); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+    }
+    s := trans.String()
+    if math.IsInf(value, 1) {
+      if s != JsonQuote(JSON_INFINITY) {
+        t.Fatalf("Bad value for %s %v, wrote: %v, expected: %v", thetype, value, s, JsonQuote(JSON_INFINITY))
+      }
+    } else if math.IsInf(value, -1) {
+      if s != JsonQuote(JSON_NEGATIVE_INFINITY) {
+        t.Fatalf("Bad value for %s %v, wrote: %v, expected: %v", thetype, value, s, JsonQuote(JSON_NEGATIVE_INFINITY))
+      }
+    } else if math.IsNaN(value) {
+      if s != JsonQuote(JSON_NAN) {
+        t.Fatalf("Bad value for %s %v, wrote: %v, expected: %v", thetype, value, s, JsonQuote(JSON_NAN))
+      }
+    } else {
+      if s != fmt.Sprint(value) {
+        t.Fatalf("Bad value for %s %v: %s", thetype, value, s)
+      }
+      v := float64(0)
+      if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+        t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+      }
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestReadJSONProtocolDouble(t *testing.T) {
+  thetype := "double"
+  for _, value := range DOUBLE_VALUES {
+    trans := NewTMemoryBuffer()
+    p := NewTJSONProtocol(trans)
+    n := NewNumericFromDouble(value)
+    trans.WriteString(n.String())
+    trans.Flush()
+    s := trans.String()
+    v, e := p.ReadDouble()
+    if e != nil {
+      t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if math.IsInf(value, 1) {
+      if !math.IsInf(v, 1) {
+        t.Fatalf("Bad value for %s %v, wrote: %v, received: %v", thetype, value, s, v)
+      }
+    } else if math.IsInf(value, -1) {
+      if !math.IsInf(v, -1) {
+        t.Fatalf("Bad value for %s %v, wrote: %v, received: %v", thetype, value, s, v)
+      }
+    } else if math.IsNaN(value) {
+      if !math.IsNaN(v) {
+        t.Fatalf("Bad value for %s %v, wrote: %v, received: %v", thetype, value, s, v)
+      }
+    } else {
+      if v != value {
+        t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+      }
+      if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+        t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+      }
+    }
+    trans.Reset()
+    trans.Close()
+  }
+}
+
+func TestWriteJSONProtocolString(t *testing.T) {
+  thetype := "string"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  for _, value := range STRING_VALUES {
+    if e := p.WriteString(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if e := p.Flush(); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+    }
+    s := trans.String()
+    if s[0] != '"' || s[len(s)-1] != '"' {
+      t.Fatalf("Bad value for %s '%v', wrote '%v', expected: %v", thetype, value, s, fmt.Sprint("\"", value, "\""))
+    }
+    v := new(string)
+    if err := json.Unmarshal([]byte(s), v); err != nil || *v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, *v)
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestReadJSONProtocolString(t *testing.T) {
+  thetype := "string"
+  for _, value := range STRING_VALUES {
+    trans := NewTMemoryBuffer()
+    p := NewTJSONProtocol(trans)
+    trans.WriteString(JsonQuote(value))
+    trans.Flush()
+    s := trans.String()
+    v, e := p.ReadString()
+    if e != nil {
+      t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if v != value {
+      t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+    }
+    v1 := new(string)
+    if err := json.Unmarshal([]byte(s), v1); err != nil || *v1 != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, *v1)
+    }
+    trans.Reset()
+    trans.Close()
+  }
+}
+
+func TestWriteJSONProtocolBinary(t *testing.T) {
+  thetype := "binary"
+  value := protocol_bdata
+  b64value := make([]byte, base64.StdEncoding.EncodedLen(len(protocol_bdata)))
+  base64.StdEncoding.Encode(b64value, value)
+  b64String := string(b64value)
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  if e := p.WriteBinary(value); e != nil {
+    t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+  }
+  if e := p.Flush(); e != nil {
+    t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+  }
+  s := trans.String()
+  expectedString := fmt.Sprint("\"", b64String, "\"")
+  if s != expectedString {
+    t.Fatalf("Bad value for %s %v\n  wrote:  \"%v\"\nexpected: \"%v\"", thetype, value, s, expectedString)
+  }
+  v1, err := p.ReadBinary()
+  if err != nil {
+    t.Fatalf("Unable to read binary: %s", err.String())
+  }
+  if len(v1) != len(value) {
+    t.Fatalf("Invalid value for binary\nexpected: \"%v\"\n   read: \"%v\"", value, v1)
+  }
+  for k, v := range value {
+    if v1[k] != v {
+      t.Fatalf("Invalid value for binary at %v\nexpected: \"%v\"\n   read: \"%v\"", k, v, v1[k])
+    }
+  }
+  trans.Close()
+}
+
+func TestReadJSONProtocolBinary(t *testing.T) {
+  thetype := "binary"
+  value := protocol_bdata
+  b64value := make([]byte, base64.StdEncoding.EncodedLen(len(protocol_bdata)))
+  base64.StdEncoding.Encode(b64value, value)
+  b64String := string(b64value)
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  trans.WriteString(JsonQuote(b64String))
+  trans.Flush()
+  s := trans.String()
+  v, e := p.ReadBinary()
+  if e != nil {
+    t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+  }
+  if len(v) != len(value) {
+    t.Fatalf("Bad value for %s value length %v, wrote: %v, received length: %v", thetype, len(value), s, len(v))
+  }
+  for i := 0; i < len(v); i++ {
+    if v[i] != value[i] {
+      t.Fatalf("Bad value for %s at index %d value %v, wrote: %v, received: %v", thetype, i, value[i], s, v[i])
+    }
+  }
+  v1 := new(string)
+  if err := json.Unmarshal([]byte(s), v1); err != nil || *v1 != b64String {
+    t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, *v1)
+  }
+  trans.Reset()
+  trans.Close()
+}
+
+func TestWriteJSONProtocolList(t *testing.T) {
+  thetype := "list"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  p.WriteListBegin(TType(DOUBLE), len(DOUBLE_VALUES))
+  for _, value := range DOUBLE_VALUES {
+    if e := p.WriteDouble(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+  }
+  p.WriteListEnd()
+  if e := p.Flush(); e != nil {
+    t.Fatalf("Unable to write %s due to error flushing: %s", thetype, e.String())
+  }
+  str := trans.String()
+  str1 := new([]interface{})
+  err := json.Unmarshal([]byte(str), str1)
+  if err != nil {
+    t.Fatalf("Unable to decode %s, wrote: %s", thetype, str)
+  }
+  l := *str1
+  if len(l) < 2 {
+    t.Fatalf("List must be at least of length two to include metadata")
+  }
+  if int(l[0].(float64)) != DOUBLE {
+    t.Fatal("Invalid type for list, expected: ", DOUBLE, ", but was: ", l[0])
+  }
+  if int(l[1].(float64)) != len(DOUBLE_VALUES) {
+    t.Fatal("Invalid length for list, expected: ", len(DOUBLE_VALUES), ", but was: ", l[1])
+  }
+  for k, value := range DOUBLE_VALUES {
+    s := l[k+2]
+    if math.IsInf(value, 1) {
+      if s.(string) != JSON_INFINITY {
+        t.Fatalf("Bad value for %s at index %v %v, wrote: %q, expected: %q, originally wrote: %q", thetype, k, value, s, JsonQuote(JSON_INFINITY), str)
+      }
+    } else if math.IsInf(value, 0) {
+      if s.(string) != JSON_NEGATIVE_INFINITY {
+        t.Fatalf("Bad value for %s at index %v %v, wrote: %q, expected: %q, originally wrote: %q", thetype, k, value, s, JsonQuote(JSON_NEGATIVE_INFINITY), str)
+      }
+    } else if math.IsNaN(value) {
+      if s.(string) != JSON_NAN {
+        t.Fatalf("Bad value for %s at index %v  %v, wrote: %q, expected: %q, originally wrote: %q", thetype, k, value, s, JsonQuote(JSON_NAN), str)
+      }
+    } else {
+      if s.(float64) != value {
+        t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s'", thetype, value, s)
+      }
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestWriteJSONProtocolSet(t *testing.T) {
+  thetype := "set"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  p.WriteSetBegin(TType(DOUBLE), len(DOUBLE_VALUES))
+  for _, value := range DOUBLE_VALUES {
+    if e := p.WriteDouble(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+  }
+  p.WriteSetEnd()
+  if e := p.Flush(); e != nil {
+    t.Fatalf("Unable to write %s due to error flushing: %s", thetype, e.String())
+  }
+  str := trans.String()
+  str1 := new([]interface{})
+  err := json.Unmarshal([]byte(str), str1)
+  if err != nil {
+    t.Fatalf("Unable to decode %s, wrote: %s", thetype, str)
+  }
+  l := *str1
+  if len(l) < 2 {
+    t.Fatalf("Set must be at least of length two to include metadata")
+  }
+  if int(l[0].(float64)) != DOUBLE {
+    t.Fatal("Invalid type for set, expected: ", DOUBLE, ", but was: ", l[0])
+  }
+  if int(l[1].(float64)) != len(DOUBLE_VALUES) {
+    t.Fatal("Invalid length for set, expected: ", len(DOUBLE_VALUES), ", but was: ", l[1])
+  }
+  for k, value := range DOUBLE_VALUES {
+    s := l[k+2]
+    if math.IsInf(value, 1) {
+      if s.(string) != JSON_INFINITY {
+        t.Fatalf("Bad value for %s at index %v %v, wrote: %q, expected: %q, originally wrote: %q", thetype, k, value, s, JsonQuote(JSON_INFINITY), str)
+      }
+    } else if math.IsInf(value, 0) {
+      if s.(string) != JSON_NEGATIVE_INFINITY {
+        t.Fatalf("Bad value for %s at index %v %v, wrote: %q, expected: %q, originally wrote: %q", thetype, k, value, s, JsonQuote(JSON_NEGATIVE_INFINITY), str)
+      }
+    } else if math.IsNaN(value) {
+      if s.(string) != JSON_NAN {
+        t.Fatalf("Bad value for %s at index %v  %v, wrote: %q, expected: %q, originally wrote: %q", thetype, k, value, s, JsonQuote(JSON_NAN), str)
+      }
+    } else {
+      if s.(float64) != value {
+        t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s'", thetype, value, s)
+      }
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestWriteJSONProtocolMap(t *testing.T) {
+  thetype := "map"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  p.WriteMapBegin(TType(I32), TType(DOUBLE), len(DOUBLE_VALUES))
+  for k, value := range DOUBLE_VALUES {
+    if e := p.WriteI32(int32(k)); e != nil {
+      t.Fatalf("Unable to write %s key int32 value %v due to error: %s", thetype, k, e.String())
+    }
+    if e := p.WriteDouble(value); e != nil {
+      t.Fatalf("Unable to write %s value float64 value %v due to error: %s", thetype, value, e.String())
+    }
+  }
+  p.WriteMapEnd()
+  if e := p.Flush(); e != nil {
+    t.Fatalf("Unable to write %s due to error flushing: %s", thetype, e.String())
+  }
+  str := trans.String()
+  if str[0] != '[' || str[len(str)-1] != ']' {
+    t.Fatalf("Bad value for %s, wrote: %q, in go: %q", thetype, str, DOUBLE_VALUES)
+  }
+  expectedKeyType, expectedValueType, expectedSize, err := p.ReadMapBegin()
+  if err != nil {
+    t.Fatalf("Error while reading map begin: %s", err.String())
+  }
+  if expectedKeyType != I32 {
+    t.Fatal("Expected map key type ", I32, ", but was ", expectedKeyType)
+  }
+  if expectedValueType != DOUBLE {
+    t.Fatal("Expected map value type ", DOUBLE, ", but was ", expectedValueType)
+  }
+  if expectedSize != len(DOUBLE_VALUES) {
+    t.Fatal("Expected map size of ", len(DOUBLE_VALUES), ", but was ", expectedSize)
+  }
+  for k, value := range DOUBLE_VALUES {
+    ik, err := p.ReadI32()
+    if err != nil {
+      t.Fatalf("Bad key for %s index %v, wrote: %v, expected: %v, error: %s", thetype, k, ik, string(k), err.String())
+    }
+    if int(ik) != k {
+      t.Fatalf("Bad key for %s index %v, wrote: %v, expected: %v", thetype, k, ik, k)
+    }
+    dv, err := p.ReadDouble()
+    if err != nil {
+      t.Fatalf("Bad value for %s index %v, wrote: %v, expected: %v, error: %s", thetype, k, dv, value, err.String())
+    }
+    s := strconv.Ftoa64(dv, 'g', 10)
+    if math.IsInf(value, 1) {
+      if !math.IsInf(dv, 1) {
+        t.Fatalf("Bad value for %s at index %v %v, wrote: %v, expected: %v", thetype, k, value, s, JsonQuote(JSON_INFINITY))
+      }
+    } else if math.IsInf(value, 0) {
+      if !math.IsInf(dv, 0) {
+        t.Fatalf("Bad value for %s at index %v %v, wrote: %v, expected: %v", thetype, k, value, s, JsonQuote(JSON_NEGATIVE_INFINITY))
+      }
+    } else if math.IsNaN(value) {
+      if !math.IsNaN(dv) {
+        t.Fatalf("Bad value for %s at index %v  %v, wrote: %v, expected: %v", thetype, k, value, s, JsonQuote(JSON_NAN))
+      }
+    } else {
+      expected := strconv.Ftoa64(value, 'g', 10)
+      if s != expected {
+        t.Fatalf("Bad value for %s at index %v %v, wrote: %v, expected %v", thetype, k, value, s, expected)
+      }
+      v := float64(0)
+      if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+        t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+      }
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+
+func TestReadWriteJSONStruct(t *testing.T) {
+  thetype := "struct"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  orig := NewWork()
+  orig.Num1 = 25
+  orig.Num2 = 102
+  orig.Op = ADD
+  orig.Comment = "Add: 25 + 102"
+  if e := orig.Write(p); e != nil {
+    t.Fatalf("Unable to write %s value %#v due to error: %s", thetype, orig, e.String())
+  }
+  p.Flush()
+  t.Log("Memory buffer contents: ", trans.String())
+  expectedString := "{\"1\":{\"i32\":25},\"2\":{\"i32\":102},\"3\":{\"i32\":1},\"4\":{\"str\":\"Add: 25 + 102\"}}"
+  if expectedString != trans.String() {
+    t.Fatalf("Expected JSON Struct with value %#v but have %#v", expectedString, trans.String())
+  }
+  read := NewWork()
+  e := read.Read(p)
+  t.Logf("Read %s value: %#v", thetype, read)
+  if e != nil {
+    t.Fatalf("Unable to read %s due to error: %s", thetype, e.String())
+  }
+  if !orig.Equals(read) {
+    t.Fatalf("Original Write != Read: %#v != %#v ", orig, read)
+  }
+}
+
+func TestReadWriteJSONProtocol(t *testing.T) {
+  ReadWriteProtocolTest(t, NewTJSONProtocolFactory())
+}
diff --git a/lib/go/thrift/tlist.go b/lib/go/thrift/tlist.go
new file mode 100644
index 0000000..778fc3b
--- /dev/null
+++ b/lib/go/thrift/tlist.go
@@ -0,0 +1,222 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "container/vector"
+)
+
+/**
+ * Helper class that encapsulates list metadata.
+ *
+ */
+type TList interface {
+  TContainer
+  ElemType() TType
+  At(i int) interface{}
+  Set(i int, data interface{})
+  Push(data interface{})
+  Pop() interface{}
+  Swap(i, j int)
+  Insert(i int, data interface{})
+  Delete(i int)
+  Less(i, j int) bool
+  Iter() <-chan interface{}
+}
+
+type tList struct {
+  elemType TType
+  l        *vector.Vector
+}
+
+func NewTList(t TType, s int) TList {
+  var v vector.Vector
+  return &tList{elemType: t, l: v.Resize(s, s)}
+}
+
+func NewTListDefault() TList {
+  var v vector.Vector
+  return &tList{elemType: TType(STOP), l: &v}
+}
+
+func (p *tList) ElemType() TType {
+  return p.elemType
+}
+
+func (p *tList) Len() int {
+  return p.l.Len()
+}
+
+func (p *tList) At(i int) interface{} {
+  return p.l.At(i)
+}
+
+func (p *tList) Set(i int, data interface{}) {
+  if p.elemType.IsEmptyType() {
+    p.elemType = TypeFromValue(data)
+  }
+  if data, ok := p.elemType.CoerceData(data); ok {
+    p.l.Set(i, data)
+  }
+}
+
+func (p *tList) Push(data interface{}) {
+  if p.elemType.IsEmptyType() {
+    p.elemType = TypeFromValue(data)
+  }
+  data, ok := p.elemType.CoerceData(data)
+  if ok {
+    p.l.Push(data)
+  }
+}
+
+func (p *tList) Pop() interface{} {
+  return p.l.Pop()
+}
+
+func (p *tList) Swap(i, j int) {
+  p.l.Swap(i, j)
+}
+
+func (p *tList) Insert(i int, data interface{}) {
+  p.l.Insert(i, data)
+}
+
+func (p *tList) Delete(i int) {
+  p.l.Delete(i)
+}
+
+func (p *tList) Contains(data interface{}) bool {
+  return p.indexOf(data) >= 0
+}
+
+func (p *tList) Less(i, j int) bool {
+  return p.l.Less(i, j)
+}
+
+func (p *tList) Iter() <-chan interface{} {
+  c := make(chan interface{})
+  go p.iterate(c)
+  return c
+}
+
+func (p *tList) iterate(c chan<- interface{}) {
+  for _, elem := range *p.l {
+    c <- elem
+  }
+  close(c)
+}
+
+func (p *tList) indexOf(data interface{}) int {
+  if data == nil {
+    size := p.l.Len()
+    for i := 0; i < size; i++ {
+      if p.l.At(i) == nil {
+        return i
+      }
+    }
+    return -1
+  }
+  data, ok := p.elemType.CoerceData(data)
+  if data == nil || !ok {
+    return -1
+  }
+  size := p.l.Len()
+  if p.elemType.IsBaseType() || p.elemType.IsEnum() {
+    for i := 0; i < size; i++ {
+      if data == p.l.At(i) {
+        return i
+      }
+    }
+    return -1
+  }
+  if cmp, ok := data.(EqualsOtherInterface); ok {
+    for i := 0; i < size; i++ {
+      if cmp.Equals(p.l.At(i)) {
+        return i
+      }
+    }
+    return -1
+  }
+  switch p.elemType {
+  case MAP:
+    if cmp, ok := data.(EqualsMap); ok {
+      for i := 0; i < size; i++ {
+        v := p.l.At(i)
+        if v == nil {
+          continue
+        }
+        if cmp.Equals(v.(TMap)) {
+          return i
+        }
+      }
+      return -1
+    }
+  case SET:
+    if cmp, ok := data.(EqualsSet); ok {
+      for i := 0; i < size; i++ {
+        v := p.l.At(i)
+        if v == nil {
+          continue
+        }
+        if cmp.Equals(v.(TSet)) {
+          return i
+        }
+      }
+      return -1
+    }
+  case LIST:
+    if cmp, ok := data.(EqualsList); ok {
+      for i := 0; i < size; i++ {
+        v := p.l.At(i)
+        if v == nil {
+          continue
+        }
+        if cmp.Equals(v.(TList)) {
+          return i
+        }
+      }
+      return -1
+    }
+  case STRUCT:
+    if cmp, ok := data.(EqualsStruct); ok {
+      for i := 0; i < size; i++ {
+        v := p.l.At(i)
+        if v == nil {
+          continue
+        }
+        if cmp.Equals(v.(TStruct)) {
+          return i
+        }
+      }
+      return -1
+    }
+  }
+  return -1
+}
+
+func (p *tList) Equals(other interface{}) bool {
+  c, cok := p.CompareTo(other)
+  return cok && c == 0
+}
+
+func (p *tList) CompareTo(other interface{}) (int, bool) {
+  return TType(LIST).Compare(p, other)
+}
diff --git a/lib/go/thrift/tmap.go b/lib/go/thrift/tmap.go
new file mode 100644
index 0000000..d042f05
--- /dev/null
+++ b/lib/go/thrift/tmap.go
@@ -0,0 +1,763 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "container/list"
+  "reflect"
+)
+
+/**
+ * Helper class that encapsulates map metadata.
+ *
+ */
+type TMap interface {
+  KeyType() TType
+  ValueType() TType
+  Len() int
+  Set(key, value interface{})
+  Get(key interface{}) (interface{}, bool)
+  Contains(key interface{}) bool
+  Iter() <-chan TMapElem
+  KeyIter() <-chan interface{}
+  ValueIter() <-chan interface{}
+  Keys() []interface{}
+  Values() []interface{}
+  Less(other interface{}) bool
+  Equals(other interface{}) bool
+  CompareTo(other interface{}) (int, bool)
+}
+
+type TMapElem interface {
+  Key() interface{}
+  Value() interface{}
+}
+
+type tMap struct {
+  keyType   TType
+  valueType TType
+  size      int
+  l         *list.List
+  b         map[bool]interface{}
+  i08       map[byte]interface{}
+  i16       map[int16]interface{}
+  i32       map[int32]interface{}
+  i64       map[int64]interface{}
+  f64       map[float64]interface{}
+  s         map[string]interface{}
+}
+
+type tMapElem struct {
+  key   interface{}
+  value interface{}
+}
+
+func (p *tMapElem) Key() interface{} {
+  return p.key
+}
+
+func (p *tMapElem) Value() interface{} {
+  return p.value
+}
+
+func NewTMapElem(k, v interface{}) TMapElem {
+  return &tMapElem{key: k, value: v}
+}
+
+func NewTMap(k, v TType, s int) TMap {
+  return &tMap{keyType: k, valueType: v, size: s, l: list.New()}
+}
+
+func NewTMapDefault() TMap {
+  return NewTMap(STOP, STOP, 0)
+}
+
+func (p *tMap) KeyType() TType {
+  return p.keyType
+}
+
+func (p *tMap) ValueType() TType {
+  return p.valueType
+}
+
+func (p *tMap) Len() int {
+  if p.l.Len() != 0 {
+    return p.l.Len()
+  }
+  switch p.KeyType() {
+  case STOP, VOID:
+    return 0
+  case BOOL:
+    return len(p.b)
+  case BYTE:
+    return len(p.i08)
+  case I16:
+    return len(p.i16)
+  case I32:
+    return len(p.i32)
+  case I64:
+    return len(p.i64)
+  case DOUBLE:
+    return len(p.f64)
+  case STRING, UTF8, UTF16:
+    return len(p.s)
+  default:
+    return p.size
+  }
+  return p.size
+}
+
+func (p *tMap) Get(key interface{}) (interface{}, bool) {
+  if p.KeyType().IsEmptyType() {
+    return nil, false
+  }
+  if key == nil {
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      e := elem.Value.(TMapElem)
+      k := e.Key()
+      if k == nil {
+        return e.Value(), true
+      }
+    }
+    return nil, false
+  }
+  useKey, ok := p.KeyType().CoerceData(key)
+  if !ok {
+    return nil, false
+  }
+  switch p.KeyType() {
+  case STOP, VOID:
+    // if here, then we don't have a key type yet and key is not nil
+    // so this is pretty much an empty map
+    return nil, false
+  case BOOL:
+    m := p.b
+    if m == nil {
+      return nil, false
+    }
+    if v, ok := m[useKey.(bool)]; ok {
+      return v, true
+    }
+    return nil, true
+  case BYTE:
+    m := p.i08
+    if v, ok := m[useKey.(byte)]; ok {
+      return v, true
+    }
+    return nil, false
+  case DOUBLE:
+    m := p.f64
+    if m == nil {
+      return nil, false
+    }
+    if v, ok := m[useKey.(float64)]; ok {
+      return v, true
+    }
+    return nil, false
+  case I16:
+    m := p.i16
+    if m == nil {
+      return nil, false
+    }
+    if v, ok := m[useKey.(int16)]; ok {
+      return v, true
+    }
+    return nil, false
+  case I32:
+    m := p.i32
+    if m == nil {
+      return nil, false
+    }
+    if v, ok := m[useKey.(int32)]; ok {
+      return v, true
+    }
+    return nil, false
+  case I64:
+    m := p.i64
+    if m == nil {
+      return nil, false
+    }
+    if v, ok := m[useKey.(int64)]; ok {
+      return v, true
+    }
+    return nil, false
+  case STRING, UTF8, UTF16:
+    // TODO(pomack) properly handle ENUM
+    m := p.s
+    if m == nil {
+      return nil, false
+    }
+    if v, ok := m[useKey.(string)]; ok {
+      return v, true
+    }
+    return nil, false
+  case STRUCT:
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      e := elem.Value.(TMapElem)
+      k := e.Key()
+      if k == nil {
+        continue
+      }
+      structkey, ok := k.(TStruct)
+      if ok {
+        if structkey.Equals(useKey.(TStruct)) {
+          return e.Value(), true
+        }
+        continue
+      }
+      if reflect.DeepEqual(useKey, k) {
+        return e.Value(), true
+      }
+    }
+    return nil, false
+  case MAP:
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      e := elem.Value.(TMapElem)
+      k := e.Key()
+      if k == nil {
+        continue
+      }
+      mapkey, ok := k.(TMap)
+      if ok {
+        if mapkey.Equals(useKey.(TMap)) {
+          return e.Value(), true
+        }
+        continue
+      }
+      if reflect.DeepEqual(useKey, k) {
+        return e.Value(), true
+      }
+    }
+    return nil, false
+  case SET:
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      e := elem.Value.(TMapElem)
+      k := e.Key()
+      if k == nil {
+        continue
+      }
+      setkey, ok := k.(TSet)
+      if ok {
+        if setkey.Equals(useKey.(TSet)) {
+          return e.Value(), true
+        }
+        continue
+      }
+      if reflect.DeepEqual(useKey, k) {
+        return e.Value(), true
+      }
+    }
+    return nil, false
+  case LIST:
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      e := elem.Value.(TMapElem)
+      k := e.Key()
+      if k == nil {
+        continue
+      }
+      listkey, ok := k.(TList)
+      if ok {
+        if listkey.Equals(useKey.(TList)) {
+          return e.Value(), true
+        }
+        continue
+      }
+      if reflect.DeepEqual(useKey, k) {
+        return e.Value(), true
+      }
+    }
+    return nil, false
+  default:
+    panic("Invalid Thrift element type")
+  }
+  return nil, false
+}
+
+
+func (p *tMap) Set(key, value interface{}) {
+  if p.KeyType() == STOP || p.KeyType() == VOID {
+    p.keyType = TypeFromValue(key)
+  }
+  coercedKey, ok := p.KeyType().CoerceData(key)
+  if !ok {
+    return
+  }
+  if p.ValueType() == STOP || p.ValueType() == VOID {
+    p.valueType = TypeFromValue(value)
+  }
+  coercedValue, ok := p.ValueType().CoerceData(value)
+  if !ok {
+    return
+  }
+  newElem := NewTMapElem(coercedKey, coercedValue)
+  if !p.KeyType().IsBaseType() {
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      k := elem.Value.(TMapElem).Key()
+      if cmp, ok := p.KeyType().Compare(coercedKey, k); ok && cmp >= 0 {
+        if cmp == 0 {
+          p.l.InsertAfter(newElem, elem)
+          p.l.Remove(elem)
+          return
+        }
+        p.l.InsertBefore(newElem, elem)
+        return
+      }
+    }
+    p.l.PushBack(newElem)
+    return
+  }
+  if key == nil {
+    return
+  }
+  switch p.KeyType() {
+  case STOP, VOID:
+    // if here, then we don't have a key type yet and key is not nil
+    // so this is pretty much an empty map
+    return
+  case BOOL:
+    if p.b == nil {
+      p.b = make(map[bool]interface{})
+    }
+    b := coercedKey.(bool)
+    p.b[b] = value
+  case BYTE:
+    if p.i08 == nil {
+      p.i08 = make(map[byte]interface{})
+    }
+    b := coercedKey.(byte)
+    p.i08[b] = value
+  case DOUBLE:
+    if p.f64 == nil {
+      p.f64 = make(map[float64]interface{})
+    }
+    b := coercedKey.(float64)
+    p.f64[b] = value
+  case I16:
+    if p.i16 == nil {
+      p.i16 = make(map[int16]interface{})
+    }
+    b := coercedKey.(int16)
+    p.i16[b] = value
+  case I32:
+    if p.i32 == nil {
+      p.i32 = make(map[int32]interface{})
+    }
+    b := coercedKey.(int32)
+    p.i32[b] = value
+  case I64:
+    if p.i64 == nil {
+      p.i64 = make(map[int64]interface{})
+    }
+    b := coercedKey.(int64)
+    p.i64[b] = value
+  case STRING, UTF8, UTF16:
+    if p.s == nil {
+      p.s = make(map[string]interface{})
+    }
+    b := coercedKey.(string)
+    p.s[b] = value
+  case STRUCT, MAP, SET, LIST:
+    panic("Should never be here")
+  default:
+    panic("Should never be here")
+  }
+}
+
+func (p *tMap) Contains(key interface{}) bool {
+  coercedKey, ok := p.KeyType().CoerceData(key)
+  if !ok {
+    return false
+  }
+  if coercedKey == nil {
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      k := elem.Value.(TMapElem).Key()
+      if k == nil {
+        return true
+      }
+    }
+    return false
+  }
+  if !ok {
+    return false
+  }
+  switch p.KeyType() {
+  case STOP:
+    // if here, then we don't have a key type yet and key is not nil
+    // so this is pretty much an empty map
+    return false
+  case VOID:
+    // if here, then we don't have a key type yet and key is not nil
+    // so this is pretty much an empty map
+    return false
+  case BOOL:
+    m := p.b
+    if m == nil {
+      return false
+    }
+    _, ok := m[coercedKey.(bool)]
+    return ok
+  case BYTE:
+    m := p.i08
+    _, ok := m[coercedKey.(byte)]
+    return ok
+  case DOUBLE:
+    m := p.f64
+    if m == nil {
+      return false
+    }
+    _, ok := m[coercedKey.(float64)]
+    return ok
+  case I16:
+    m := p.i16
+    if m == nil {
+      return false
+    }
+    _, ok := m[coercedKey.(int16)]
+    return ok
+  case I32:
+    m := p.i32
+    if m == nil {
+      return false
+    }
+    _, ok := m[coercedKey.(int32)]
+    return ok
+  case I64:
+    m := p.i64
+    if m == nil {
+      return false
+    }
+    _, ok := m[coercedKey.(int64)]
+    return ok
+  case STRING, UTF8, UTF16:
+    // TODO(pomack) properly handle ENUM
+    m := p.s
+    if m == nil {
+      return false
+    }
+    _, ok := m[coercedKey.(string)]
+    return ok
+  case STRUCT:
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      e := elem.Value.(TMapElem)
+      k := e.Key()
+      if k == nil {
+        continue
+      }
+      structkey, ok := k.(TStruct)
+      if ok {
+        if structkey.Equals(coercedKey.(TStruct)) {
+          return true
+        }
+        continue
+      }
+      if reflect.DeepEqual(coercedKey, k) {
+        return true
+      }
+    }
+    return false
+  case MAP:
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      e := elem.Value.(TMapElem)
+      k := e.Key()
+      if k == nil {
+        continue
+      }
+      mapkey, ok := k.(TMap)
+      if ok {
+        if mapkey.Equals(coercedKey.(TMap)) {
+          return true
+        }
+        continue
+      }
+    }
+    return false
+  case SET:
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      e := elem.Value.(TMapElem)
+      k := e.Key()
+      if k == nil {
+        continue
+      }
+      setkey, ok := k.(TSet)
+      if ok {
+        if setkey.Equals(coercedKey.(TSet)) {
+          return true
+        }
+        continue
+      }
+    }
+    return false
+  case LIST:
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      e := elem.Value.(TMapElem)
+      k := e.Key()
+      if k == nil {
+        continue
+      }
+      listkey, ok := k.(TList)
+      if ok {
+        if listkey.Equals(coercedKey.(TList)) {
+          return true
+        }
+        continue
+      }
+    }
+    return false
+  default:
+    panic("Invalid Thrift element type")
+  }
+  return false
+}
+
+// Iterate over all elements; driver for range
+func (p *tMap) iterate(c chan<- TMapElem) {
+  switch p.KeyType() {
+  case STOP, VOID:
+    close(c)
+  case BOOL:
+    for k, v := range p.b {
+      c <- NewTMapElem(k, v)
+    }
+    close(c)
+  case BYTE:
+    for k, v := range p.i08 {
+      c <- NewTMapElem(k, v)
+    }
+    close(c)
+  case I16:
+    for k, v := range p.i16 {
+      c <- NewTMapElem(k, v)
+    }
+    close(c)
+  case I32:
+    for k, v := range p.i32 {
+      c <- NewTMapElem(k, v)
+    }
+    close(c)
+  case I64:
+    for k, v := range p.i64 {
+      c <- NewTMapElem(k, v)
+    }
+    close(c)
+  case DOUBLE:
+    for k, v := range p.f64 {
+      c <- NewTMapElem(k, v)
+    }
+    close(c)
+  case STRING, UTF8, UTF16:
+    for k, v := range p.s {
+      c <- NewTMapElem(k, v)
+    }
+    close(c)
+  case STRUCT:
+    for v := p.l.Front(); v != nil; v = v.Next() {
+      c <- v.Value.(TMapElem)
+    }
+    close(c)
+  case LIST:
+    for v := p.l.Front(); v != nil; v = v.Next() {
+      c <- v.Value.(TMapElem)
+    }
+    close(c)
+  case SET:
+    for v := p.l.Front(); v != nil; v = v.Next() {
+      c <- v.Value.(TMapElem)
+    }
+    close(c)
+  default:
+    panic("Invalid Thrift type")
+  }
+}
+
+// Channel iterator for range.
+func (p *tMap) Iter() <-chan TMapElem {
+  c := make(chan TMapElem)
+  go p.iterate(c)
+  return c
+}
+
+// Iterate over all keys; driver for range
+func (p *tMap) iterateKeys(c chan<- interface{}) {
+  switch p.KeyType() {
+  case STOP, VOID:
+    close(c)
+  case BOOL:
+    for k, _ := range p.b {
+      c <- k
+    }
+    close(c)
+  case BYTE:
+    for k, _ := range p.i08 {
+      c <- k
+    }
+    close(c)
+  case I16:
+    for k, _ := range p.i16 {
+      c <- k
+    }
+    close(c)
+  case I32:
+    for k, _ := range p.i32 {
+      c <- k
+    }
+    close(c)
+  case I64:
+    for k, _ := range p.i64 {
+      c <- k
+    }
+    close(c)
+  case DOUBLE:
+    for k, _ := range p.f64 {
+      c <- k
+    }
+    close(c)
+  case STRING, UTF8, UTF16:
+    for k, _ := range p.s {
+      c <- k
+    }
+    close(c)
+  case STRUCT:
+    for v := p.l.Front(); v != nil; v = v.Next() {
+      c <- v.Value.(TMapElem).Key()
+    }
+    close(c)
+  case LIST:
+    for v := p.l.Front(); v != nil; v = v.Next() {
+      c <- v.Value.(TMapElem).Key()
+    }
+    close(c)
+  case SET:
+    for v := p.l.Front(); v != nil; v = v.Next() {
+      c <- v.Value.(TMapElem).Key()
+    }
+    close(c)
+  default:
+    panic("Invalid Thrift type")
+  }
+}
+
+func (p *tMap) KeyIter() <-chan interface{} {
+  c := make(chan interface{})
+  go p.iterateKeys(c)
+  return c
+}
+
+// Iterate over all values; driver for range
+func (p *tMap) iterateValues(c chan<- interface{}) {
+  switch p.KeyType() {
+  case STOP, VOID:
+    close(c)
+  case BOOL:
+    for _, v := range p.b {
+      c <- v
+    }
+    close(c)
+  case BYTE:
+    for _, v := range p.i08 {
+      c <- v
+    }
+    close(c)
+  case I16:
+    for _, v := range p.i16 {
+      c <- v
+    }
+    close(c)
+  case I32:
+    for _, v := range p.i32 {
+      c <- v
+    }
+    close(c)
+  case I64:
+    for _, v := range p.i64 {
+      c <- v
+    }
+    close(c)
+  case DOUBLE:
+    for _, v := range p.f64 {
+      c <- v
+    }
+    close(c)
+  case STRING, UTF8, UTF16:
+    for _, v := range p.s {
+      c <- v
+    }
+    close(c)
+  case STRUCT:
+    for v := p.l.Front(); v != nil; v = v.Next() {
+      c <- v.Value.(TMapElem).Value()
+    }
+    close(c)
+  case LIST:
+    for v := p.l.Front(); v != nil; v = v.Next() {
+      c <- v.Value.(TMapElem).Value()
+    }
+    close(c)
+  case SET:
+    for v := p.l.Front(); v != nil; v = v.Next() {
+      c <- v.Value.(TMapElem).Value()
+    }
+    close(c)
+  default:
+    panic("Invalid Thrift type")
+  }
+}
+
+func (p *tMap) ValueIter() <-chan interface{} {
+  c := make(chan interface{})
+  go p.iterateValues(c)
+  return c
+}
+
+
+func (p *tMap) Less(other interface{}) bool {
+  cmp, ok := p.CompareTo(other)
+  return ok && cmp > 0
+}
+
+func (p *tMap) Equals(other interface{}) bool {
+  c, cok := p.CompareTo(other)
+  return cok && c == 0
+}
+
+func (p *tMap) CompareTo(other interface{}) (int, bool) {
+  return TType(MAP).Compare(p, other)
+}
+
+func (p *tMap) Keys() []interface{} {
+  size := p.Len()
+  values := make([]interface{}, size, size)
+  i := 0
+  for k := range p.KeyIter() {
+    values[i] = k
+    i++
+  }
+  return values
+}
+
+func (p *tMap) Values() []interface{} {
+  size := p.Len()
+  values := make([]interface{}, size, size)
+  i := 0
+  for v := range p.ValueIter() {
+    values[i] = v
+    i++
+  }
+  return values
+}
diff --git a/lib/go/thrift/tmemory_buffer.go b/lib/go/thrift/tmemory_buffer.go
new file mode 100644
index 0000000..69b794e
--- /dev/null
+++ b/lib/go/thrift/tmemory_buffer.go
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "bytes"
+  "io"
+  "os"
+)
+
+/**
+ * Memory buffer-based implementation of the TTransport interface.
+ *
+ */
+type TMemoryBuffer struct {
+  buf  *bytes.Buffer
+  size int
+}
+
+type TMemoryBufferTransportFactory struct {
+  size int
+}
+
+func (p *TMemoryBufferTransportFactory) GetTransport(trans TTransport) TTransport {
+  if trans != nil {
+    t, ok := trans.(*TMemoryBuffer)
+    if ok && t.size > 0 {
+      return NewTMemoryBufferLen(t.size)
+    }
+  }
+  return NewTMemoryBufferLen(p.size)
+}
+
+func NewTMemoryBufferTransportFactory(size int) *TMemoryBufferTransportFactory {
+  return &TMemoryBufferTransportFactory{size: size}
+}
+
+func NewTMemoryBuffer() *TMemoryBuffer {
+  return &TMemoryBuffer{buf: &bytes.Buffer{}, size: 0}
+}
+
+func NewTMemoryBufferLen(size int) *TMemoryBuffer {
+  buf := make([]byte, 0, size)
+  return &TMemoryBuffer{buf: bytes.NewBuffer(buf), size: size}
+}
+
+func (p *TMemoryBuffer) IsOpen() bool {
+  return true
+}
+
+func (p *TMemoryBuffer) Open() os.Error {
+  return nil
+}
+
+func (p *TMemoryBuffer) Peek() bool {
+  return p.IsOpen()
+}
+
+func (p *TMemoryBuffer) Close() os.Error {
+  p.buf.Reset()
+  return nil
+}
+
+func (p *TMemoryBuffer) Read(buf []byte) (int, os.Error) {
+  return p.buf.Read(buf)
+}
+
+func (p *TMemoryBuffer) ReadAll(buf []byte) (int, os.Error) {
+  return ReadAllTransport(p, buf)
+}
+
+func (p *TMemoryBuffer) ReadByte() (byte, os.Error) {
+  return p.buf.ReadByte()
+}
+
+func (p *TMemoryBuffer) ReadFrom(r io.Reader) (int64, os.Error) {
+  return p.buf.ReadFrom(r)
+}
+
+func (p *TMemoryBuffer) Write(buf []byte) (int, os.Error) {
+  return p.buf.Write(buf)
+}
+
+func (p *TMemoryBuffer) WriteString(buf string) (int, os.Error) {
+  return p.buf.WriteString(buf)
+}
+
+func (p *TMemoryBuffer) WriteTo(w io.Writer) (int64, os.Error) {
+  return p.buf.WriteTo(w)
+}
+
+func (p *TMemoryBuffer) Flush() os.Error {
+  return nil
+}
+
+func (p *TMemoryBuffer) Reset() {
+  p.buf.Reset()
+}
+
+func (p *TMemoryBuffer) Bytes() []byte {
+  return p.buf.Bytes()
+}
+
+func (p *TMemoryBuffer) Len() int {
+  return p.buf.Len()
+}
+
+func (p *TMemoryBuffer) String() string {
+  return p.buf.String()
+}
diff --git a/lib/go/thrift/tmemory_buffer_test.go b/lib/go/thrift/tmemory_buffer_test.go
new file mode 100644
index 0000000..5d17864
--- /dev/null
+++ b/lib/go/thrift/tmemory_buffer_test.go
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package thrift_test
+
+import (
+  . "thrift"
+  "testing"
+)
+
+func TestMemoryBuffer(t *testing.T) {
+  trans := NewTMemoryBufferLen(1024)
+  TransportTest(t, trans, trans)
+}
diff --git a/lib/go/thrift/tmessage.go b/lib/go/thrift/tmessage.go
new file mode 100644
index 0000000..c768cb4
--- /dev/null
+++ b/lib/go/thrift/tmessage.go
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+/**
+ * Helper class that encapsulates struct metadata.
+ *
+ */
+type TMessage interface {
+  Name() string
+  TypeId() TMessageType
+  SeqId() int
+  Equals(other TMessage) bool
+}
+type tMessage struct {
+  name   string
+  typeId TMessageType
+  seqid  int
+}
+
+func NewTMessageDefault() TMessage {
+  return NewTMessage("", STOP, 0)
+}
+
+func NewTMessage(n string, t TMessageType, s int) TMessage {
+  return &tMessage{name: n, typeId: t, seqid: s}
+}
+
+func (p *tMessage) Name() string {
+  return p.name
+}
+
+func (p *tMessage) TypeId() TMessageType {
+  return p.typeId
+}
+
+func (p *tMessage) SeqId() int {
+  return p.seqid
+}
+
+func (p *tMessage) String() string {
+  return "<TMessage name:'" + p.name + "' type: " + string(p.typeId) + " seqid:" + string(p.seqid) + ">"
+}
+
+func (p *tMessage) Equals(other TMessage) bool {
+  return p.name == other.Name() && p.typeId == other.TypeId() && p.seqid == other.SeqId()
+}
+
+var EMPTY_MESSAGE TMessage
+
+func init() {
+  EMPTY_MESSAGE = NewTMessageDefault()
+}
diff --git a/lib/go/thrift/tmessagetype.go b/lib/go/thrift/tmessagetype.go
new file mode 100644
index 0000000..b31c66c
--- /dev/null
+++ b/lib/go/thrift/tmessagetype.go
@@ -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.
+ */
+
+package thrift
+
+/**
+ * Message type constants in the Thrift protocol.
+ *
+ */
+type TMessageType int32
+
+const (
+  INVALID_TMESSAGE_TYPE TMessageType = 0
+  CALL                  TMessageType = 1
+  REPLY                 TMessageType = 2
+  EXCEPTION             TMessageType = 3
+  ONEWAY                TMessageType = 4
+)
diff --git a/lib/go/thrift/tnonblocking_server.go b/lib/go/thrift/tnonblocking_server.go
new file mode 100644
index 0000000..e234c5a
--- /dev/null
+++ b/lib/go/thrift/tnonblocking_server.go
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "os"
+)
+
+/**
+ * A nonblocking TServer implementation. This allows for fairness amongst all
+ * connected clients in terms of invocations.
+ *
+ * This server is inherently single-threaded. If you want a limited thread pool
+ * coupled with invocation-fairness, see THsHaServer.
+ *
+ * To use this server, you MUST use a TFramedTransport at the outermost
+ * transport, otherwise this server will be unable to determine when a whole
+ * method call has been read off the wire. Clients must also use TFramedTransport.
+ */
+type TNonblockingServer struct {
+  /** Flag for stopping the server */
+  stopped bool
+
+  processorFactory       TProcessorFactory
+  serverTransport        TServerTransport
+  inputTransportFactory  TTransportFactory
+  outputTransportFactory TTransportFactory
+  inputProtocolFactory   TProtocolFactory
+  outputProtocolFactory  TProtocolFactory
+}
+
+
+func NewTNonblockingServer2(processor TProcessor, serverTransport TServerTransport) *TNonblockingServer {
+  return NewTNonblockingServerFactory2(NewTProcessorFactory(processor), serverTransport)
+}
+
+func NewTNonblockingServer4(processor TProcessor, serverTransport TServerTransport, transportFactory TTransportFactory, protocolFactory TProtocolFactory) *TNonblockingServer {
+  return NewTNonblockingServerFactory4(NewTProcessorFactory(processor),
+    serverTransport,
+    transportFactory,
+    protocolFactory,
+  )
+}
+
+func NewTNonblockingServer6(processor TProcessor, serverTransport TServerTransport, inputTransportFactory TTransportFactory, outputTransportFactory TTransportFactory, inputProtocolFactory TProtocolFactory, outputProtocolFactory TProtocolFactory) *TNonblockingServer {
+  return NewTNonblockingServerFactory6(NewTProcessorFactory(processor),
+    serverTransport,
+    inputTransportFactory,
+    outputTransportFactory,
+    inputProtocolFactory,
+    outputProtocolFactory,
+  )
+}
+
+func NewTNonblockingServerFactory2(processorFactory TProcessorFactory, serverTransport TServerTransport) *TNonblockingServer {
+  return NewTNonblockingServerFactory6(processorFactory,
+    serverTransport,
+    NewTTransportFactory(),
+    NewTTransportFactory(),
+    NewTBinaryProtocolFactoryDefault(),
+    NewTBinaryProtocolFactoryDefault(),
+  )
+}
+
+func NewTNonblockingServerFactory4(processorFactory TProcessorFactory, serverTransport TServerTransport, transportFactory TTransportFactory, protocolFactory TProtocolFactory) *TNonblockingServer {
+  return NewTNonblockingServerFactory6(processorFactory,
+    serverTransport,
+    transportFactory,
+    transportFactory,
+    protocolFactory,
+    protocolFactory,
+  )
+}
+
+func NewTNonblockingServerFactory6(processorFactory TProcessorFactory, serverTransport TServerTransport, inputTransportFactory TTransportFactory, outputTransportFactory TTransportFactory, inputProtocolFactory TProtocolFactory, outputProtocolFactory TProtocolFactory) *TNonblockingServer {
+  return &TNonblockingServer{processorFactory: processorFactory,
+    serverTransport:        serverTransport,
+    inputTransportFactory:  inputTransportFactory,
+    outputTransportFactory: outputTransportFactory,
+    inputProtocolFactory:   inputProtocolFactory,
+    outputProtocolFactory:  outputProtocolFactory,
+  }
+}
+
+func (p *TNonblockingServer) ProcessorFactory() TProcessorFactory {
+  return p.processorFactory
+}
+
+func (p *TNonblockingServer) ServerTransport() TServerTransport {
+  return p.serverTransport
+}
+
+func (p *TNonblockingServer) InputTransportFactory() TTransportFactory {
+  return p.inputTransportFactory
+}
+
+func (p *TNonblockingServer) OutputTransportFactory() TTransportFactory {
+  return p.outputTransportFactory
+}
+
+func (p *TNonblockingServer) InputProtocolFactory() TProtocolFactory {
+  return p.inputProtocolFactory
+}
+
+func (p *TNonblockingServer) OutputProtocolFactory() TProtocolFactory {
+  return p.outputProtocolFactory
+}
+
+func (p *TNonblockingServer) Serve() os.Error {
+  p.stopped = false
+  err := p.serverTransport.Listen()
+  if err != nil {
+    return err
+  }
+  for !p.stopped {
+    client, err := p.serverTransport.Accept()
+    if err != nil {
+      return err
+    }
+    if client != nil {
+      go p.processRequest(client)
+    }
+  }
+  return nil
+}
+
+func (p *TNonblockingServer) Stop() os.Error {
+  p.stopped = true
+  p.serverTransport.Interrupt()
+  return nil
+}
+
+func (p *TNonblockingServer) IsStopped() bool {
+  return p.stopped
+}
+
+func (p *TNonblockingServer) processRequest(client TTransport) {
+  processor := p.processorFactory.GetProcessor(client)
+  inputTransport := p.inputTransportFactory.GetTransport(client)
+  outputTransport := p.outputTransportFactory.GetTransport(client)
+  inputProtocol := p.inputProtocolFactory.GetProtocol(inputTransport)
+  outputProtocol := p.outputProtocolFactory.GetProtocol(outputTransport)
+  if inputTransport != nil {
+    defer inputTransport.Close()
+  }
+  if outputTransport != nil {
+    defer outputTransport.Close()
+  }
+  for {
+    ok, e := processor.Process(inputProtocol, outputProtocol)
+    if e != nil {
+      if !p.stopped {
+        // TODO(pomack) log error
+        break
+      }
+    }
+    if !ok {
+      break
+    }
+  }
+}
diff --git a/lib/go/thrift/tnonblocking_server_socket.go b/lib/go/thrift/tnonblocking_server_socket.go
new file mode 100644
index 0000000..3c9dbaa
--- /dev/null
+++ b/lib/go/thrift/tnonblocking_server_socket.go
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "net"
+  "os"
+)
+
+/**
+ * Socket implementation of the TTransport interface. To be commented soon!
+ */
+type TNonblockingServerSocket struct {
+  listener net.Listener
+  addr     net.Addr
+  /**
+   * Socket timeout
+   */
+  nsecTimeout int64
+}
+
+type TNonblockingServerSocketTransportFactory struct {
+  addr net.Addr
+}
+
+func (p *TNonblockingServerSocketTransportFactory) GetTransport(trans TTransport) TTransport {
+  if trans != nil {
+    t, ok := trans.(*TNonblockingServerSocket)
+    if ok && t.addr != nil {
+      s, _ := NewTNonblockingServerSocketAddr(t.addr)
+      s.SetTimeout(t.nsecTimeout)
+      return s
+    }
+  }
+  s, _ := NewTNonblockingServerSocketAddr(p.addr)
+  return s
+}
+
+func NewTNonblockingServerSocketTransportFactory(addr net.Addr) *TNonblockingServerSocketTransportFactory {
+  return &TNonblockingServerSocketTransportFactory{addr: addr}
+}
+
+
+func NewTNonblockingServerSocketListener(listener net.Listener) (*TNonblockingServerSocket, TTransportException) {
+  s := &TNonblockingServerSocket{listener: listener, addr: listener.Addr()}
+  return s, nil
+}
+
+func NewTNonblockingServerSocketAddr(addr net.Addr) (*TNonblockingServerSocket, TTransportException) {
+  s := &TNonblockingServerSocket{addr: addr}
+  return s, nil
+}
+
+func (p *TNonblockingServerSocket) Listen() os.Error {
+  return p.Open()
+}
+
+/**
+ * Sets the socket timeout
+ *
+ * @param timeout Nanoseconds timeout
+ */
+func (p *TNonblockingServerSocket) SetTimeout(nsecTimeout int64) os.Error {
+  p.nsecTimeout = nsecTimeout
+  return nil
+}
+
+/**
+ * Checks whether the socket is connected.
+ */
+func (p *TNonblockingServerSocket) IsOpen() bool {
+  return p.listener != nil
+}
+
+/**
+ * Connects the socket, creating a new socket object if necessary.
+ */
+func (p *TNonblockingServerSocket) Open() os.Error {
+  if !p.IsOpen() {
+    l, err := net.Listen(p.addr.Network(), p.addr.String())
+    if err != nil {
+      return err
+    }
+    p.listener = l
+    return nil
+  }
+  return NewTTransportException(ALREADY_OPEN, "Server socket already open")
+}
+
+/**
+ * Perform a nonblocking read into buffer.
+ */
+func (p *TNonblockingServerSocket) Read(buf []byte) (int, os.Error) {
+  return 0, NewTTransportException(UNKNOWN_TRANSPORT_EXCEPTION, "TNonblockingServerSocket.Read([]byte) is not implemented")
+}
+
+func (p *TNonblockingServerSocket) ReadAll(buf []byte) (int, os.Error) {
+  return ReadAllTransport(p, buf)
+}
+
+/**
+ * Perform a nonblocking write of the data in buffer;
+ */
+func (p *TNonblockingServerSocket) Write(buf []byte) (int, os.Error) {
+  return 0, NewTTransportException(UNKNOWN_TRANSPORT_EXCEPTION, "TNonblockingServerSocket.Write([]byte) is not implemented")
+}
+
+/**
+ * Flushes the underlying output stream if not null.
+ */
+func (p *TNonblockingServerSocket) Flush() os.Error {
+  return NewTTransportException(UNKNOWN_TRANSPORT_EXCEPTION, "TNonblockingServerSocket.Flush() is not implemented")
+}
+
+func (p *TNonblockingServerSocket) Addr() net.Addr {
+  return p.addr
+}
+
+func (p *TNonblockingServerSocket) Accept() (TTransport, os.Error) {
+  if !p.IsOpen() {
+    return nil, NewTTransportException(NOT_OPEN, "No underlying server socket")
+  }
+  conn, err := p.listener.Accept()
+  if err != nil {
+    return nil, NewTTransportExceptionFromOsError(err)
+  }
+  conn.SetTimeout(p.nsecTimeout)
+  return NewTSocketConn(conn)
+}
+
+func (p *TNonblockingServerSocket) Peek() bool {
+  return p.IsOpen()
+}
+
+/**
+ * Closes the socket.
+ */
+func (p *TNonblockingServerSocket) Close() (err os.Error) {
+  if p.IsOpen() {
+    err := p.listener.Close()
+    if err != nil {
+      return NewTTransportExceptionFromOsError(err)
+    }
+    p.listener = nil
+  }
+  return nil
+}
+
+func (p *TNonblockingServerSocket) Interrupt() os.Error {
+  // probably not right
+  return p.Close()
+}
diff --git a/lib/go/thrift/tnonblocking_socket.go b/lib/go/thrift/tnonblocking_socket.go
new file mode 100644
index 0000000..a1c0310
--- /dev/null
+++ b/lib/go/thrift/tnonblocking_socket.go
@@ -0,0 +1,192 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "net"
+  "os"
+)
+
+/**
+ * Socket implementation of the TTransport interface. To be commented soon!
+ */
+type TNonblockingSocket struct {
+  conn net.Conn
+  addr net.Addr
+  /**
+   * Socket timeout
+   */
+  nsecTimeout int64
+}
+
+type TNonblockingSocketTransportFactory struct {
+  addr net.Addr
+}
+
+func (p *TNonblockingSocketTransportFactory) GetTransport(trans TTransport) TTransport {
+  if trans != nil {
+    t, ok := trans.(*TNonblockingSocket)
+    if ok {
+      s, _ := NewTNonblockingSocketAddr(t.addr)
+      s.SetTimeout(t.nsecTimeout)
+      return s
+    }
+  }
+  s, _ := NewTNonblockingSocketAddr(p.addr)
+  return s
+}
+
+func NewTNonblockingSocketTransportFactory(addr net.Addr) *TNonblockingSocketTransportFactory {
+  return &TNonblockingSocketTransportFactory{addr: addr}
+}
+
+func NewTNonblockingSocketConn(conn net.Conn) (*TNonblockingSocket, TTransportException) {
+  s := &TNonblockingSocket{conn: conn, addr: conn.RemoteAddr()}
+  return s, nil
+}
+
+func NewTNonblockingSocketAddr(addr net.Addr) (*TNonblockingSocket, TTransportException) {
+  s := &TNonblockingSocket{addr: addr}
+  return s, nil
+}
+
+/**
+ * Sets the socket timeout
+ *
+ * @param nsecTimeout Nanoseconds timeout
+ */
+func (p *TNonblockingSocket) SetTimeout(nsecTimeout int64) os.Error {
+  p.nsecTimeout = nsecTimeout
+  if p.IsOpen() {
+    if err := p.conn.SetTimeout(nsecTimeout); err != nil {
+      LOGGER.Print("Could not set socket timeout.", err)
+      return err
+    }
+  }
+  return nil
+}
+
+/**
+ * Checks whether the socket is connected.
+ */
+func (p *TNonblockingSocket) IsOpen() bool {
+  return p.conn != nil
+}
+
+/**
+ * Connects the socket, creating a new socket object if necessary.
+ */
+func (p *TNonblockingSocket) Open() os.Error {
+  if p.IsOpen() {
+    return NewTTransportException(ALREADY_OPEN, "Socket already connected.")
+  }
+  if p.addr == nil {
+    return NewTTransportException(NOT_OPEN, "Cannot open nil address.")
+  }
+  if len(p.addr.Network()) == 0 {
+    return NewTTransportException(NOT_OPEN, "Cannot open bad network name.")
+  }
+  if len(p.addr.String()) == 0 {
+    return NewTTransportException(NOT_OPEN, "Cannot open bad address.")
+  }
+
+  var err os.Error
+  if p.conn, err = net.Dial(p.addr.Network(), "", p.addr.String()); err != nil {
+    LOGGER.Print("Could not open socket", err.String())
+    return NewTTransportException(NOT_OPEN, err.String())
+  }
+  if p.conn != nil {
+    p.conn.SetTimeout(p.nsecTimeout)
+  }
+  return nil
+}
+
+/**
+ * Perform a nonblocking read into buffer.
+ */
+func (p *TNonblockingSocket) Read(buf []byte) (int, os.Error) {
+  if !p.IsOpen() {
+    return 0, NewTTransportException(NOT_OPEN, "Connection not open")
+  }
+  n, err := p.conn.Read(buf)
+  return n, NewTTransportExceptionFromOsError(err)
+}
+
+
+func (p *TNonblockingSocket) ReadAll(buf []byte) (int, os.Error) {
+  return ReadAllTransport(p, buf)
+}
+
+/**
+ * Perform a nonblocking write of the data in buffer;
+ */
+func (p *TNonblockingSocket) Write(buf []byte) (int, os.Error) {
+  if !p.IsOpen() {
+    return 0, NewTTransportException(NOT_OPEN, "Connection not open")
+  }
+  return p.conn.Write(buf)
+}
+
+/**
+ * Flushes the underlying output stream if not null.
+ */
+func (p *TNonblockingSocket) Flush() os.Error {
+  if !p.IsOpen() {
+    return NewTTransportException(NOT_OPEN, "Connection not open")
+  }
+  f, ok := p.conn.(Flusher)
+  if ok {
+    err := f.Flush()
+    if err != nil {
+      return NewTTransportExceptionFromOsError(err)
+    }
+  }
+  return nil
+}
+
+func (p *TNonblockingSocket) Addr() net.Addr {
+  return p.addr
+}
+
+func (p *TNonblockingSocket) Peek() bool {
+  return p.IsOpen()
+}
+
+/**
+ * Closes the socket.
+ */
+func (p *TNonblockingSocket) Close() os.Error {
+  if p.conn != nil {
+    if err := p.conn.Close(); err != nil {
+      LOGGER.Print("Could not close socket.", err.String())
+      return err
+    }
+    p.conn = nil
+  }
+  return nil
+}
+
+func (p *TNonblockingSocket) Interrupt() os.Error {
+  if !p.IsOpen() {
+    return nil
+  }
+  // TODO(pomack) fix Interrupt as it is probably not right
+  return p.Close()
+}
diff --git a/lib/go/thrift/tnonblocking_transport.go b/lib/go/thrift/tnonblocking_transport.go
new file mode 100644
index 0000000..da9c26d
--- /dev/null
+++ b/lib/go/thrift/tnonblocking_transport.go
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+type TNonblockingTransport interface {
+  TTransport
+}
diff --git a/lib/go/thrift/tnonblocking_transport_test.go b/lib/go/thrift/tnonblocking_transport_test.go
new file mode 100644
index 0000000..7d019db
--- /dev/null
+++ b/lib/go/thrift/tnonblocking_transport_test.go
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+package thrift_test
+
+import (
+  . "thrift"
+  "testing"
+  "net"
+)
+
+func TestNonblockingTransportServerToClient(t *testing.T) {
+
+  addr, err := FindAvailableTCPServerPort(40000)
+  if err != nil {
+    t.Fatalf("Unable to find available tcp port addr: %s", err)
+  }
+  trans1, err := NewTNonblockingServerSocketAddr(addr)
+  if err != nil {
+    t.Fatalf("Unable to setup server socket listener: %s", err)
+  }
+  trans1.Open()
+  trans2, err := NewTNonblockingSocketAddr(addr)
+  if err != nil {
+    t.Fatalf("Unable to setup client socket: %s", err)
+  }
+  trans1.SetTimeout(10)
+  trans2.SetTimeout(10)
+  err = trans2.Open()
+  if err != nil {
+    t.Fatalf("Unable to connect client to server: %s", err)
+  }
+  s, err := trans1.Accept()
+  if err != nil {
+    t.Fatalf("Unable to accept client connection from server: %s", err)
+  }
+  //s.SetTimeout(10)
+  TransportTest(t, NewTFramedTransport(s), NewTFramedTransport(trans2))
+  trans1.Close()
+}
+
+func TestNonblockingTransportClientToServer(t *testing.T) {
+  addr, err := FindAvailableTCPServerPort(40000)
+  if err != nil {
+    t.Fatalf("Unable to find available tcp port addr: %s", err)
+  }
+  l, err := net.Listen(addr.Network(), addr.String())
+  if err != nil {
+    t.Fatalf("Unable to setup listener: %s", err)
+  }
+  trans1, err := NewTNonblockingServerSocketListener(l)
+  if err != nil {
+    t.Fatalf("Unable to setup server socket listener: %s", err)
+  }
+  trans2, err := NewTNonblockingSocketAddr(l.Addr())
+  if err != nil {
+    t.Fatalf("Unable to setup client socket: %s", err)
+  }
+  trans1.SetTimeout(10)
+  trans2.SetTimeout(10)
+  err = trans2.Open()
+  if err != nil {
+    t.Fatalf("Unable to connect client to server: %s", err)
+  }
+  s, err := trans1.Accept()
+  if err != nil {
+    t.Fatalf("Unable to accept client connection from server: %s", err)
+  }
+  //s.SetTimeout(10)
+  TransportTest(t, NewTFramedTransport(trans2), NewTFramedTransport(s))
+  trans1.Close()
+}
diff --git a/lib/go/thrift/tnumeric.go b/lib/go/thrift/tnumeric.go
new file mode 100644
index 0000000..b1f6508
--- /dev/null
+++ b/lib/go/thrift/tnumeric.go
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+
+package thrift
+
+import (
+  "math"
+  "strconv"
+)
+
+type Numeric interface {
+  Int64() int64
+  Int32() int32
+  Int16() int16
+  Byte() byte
+  Int() int
+  Float64() float64
+  Float32() float32
+  String() string
+  isNull() bool
+}
+
+type numeric struct {
+  iValue int64
+  dValue float64
+  sValue string
+  isNil  bool
+}
+
+var (
+  INFINITY          Numeric
+  NEGATIVE_INFINITY Numeric
+  NAN               Numeric
+  ZERO              Numeric
+  NUMERIC_NULL      Numeric
+)
+
+func NewNumericFromDouble(dValue float64) Numeric {
+  if math.IsInf(dValue, 1) {
+    return INFINITY
+  }
+  if math.IsInf(dValue, -1) {
+    return NEGATIVE_INFINITY
+  }
+  if math.IsNaN(dValue) {
+    return NAN
+  }
+  iValue := int64(dValue)
+  sValue := strconv.Ftoa64(dValue, 'g', 10)
+  isNil := false
+  return &numeric{iValue: iValue, dValue: dValue, sValue: sValue, isNil: isNil}
+}
+
+func NewNumericFromI64(iValue int64) Numeric {
+  dValue := float64(iValue)
+  sValue := string(iValue)
+  isNil := false
+  return &numeric{iValue: iValue, dValue: dValue, sValue: sValue, isNil: isNil}
+}
+
+func NewNumericFromI32(iValue int32) Numeric {
+  dValue := float64(iValue)
+  sValue := string(iValue)
+  isNil := false
+  return &numeric{iValue: int64(iValue), dValue: dValue, sValue: sValue, isNil: isNil}
+}
+
+func NewNumericFromString(sValue string) Numeric {
+  if sValue == INFINITY.String() {
+    return INFINITY
+  }
+  if sValue == NEGATIVE_INFINITY.String() {
+    return NEGATIVE_INFINITY
+  }
+  if sValue == NAN.String() {
+    return NAN
+  }
+  iValue, _ := strconv.Atoi64(sValue)
+  dValue, _ := strconv.Atof64(sValue)
+  isNil := len(sValue) == 0
+  return &numeric{iValue: iValue, dValue: dValue, sValue: sValue, isNil: isNil}
+}
+
+func NewNumericFromJSONString(sValue string, isNull bool) Numeric {
+  if isNull {
+    return NewNullNumeric()
+  }
+  if sValue == JSON_INFINITY {
+    return INFINITY
+  }
+  if sValue == JSON_NEGATIVE_INFINITY {
+    return NEGATIVE_INFINITY
+  }
+  if sValue == JSON_NAN {
+    return NAN
+  }
+  iValue, _ := strconv.Atoi64(sValue)
+  dValue, _ := strconv.Atof64(sValue)
+  return &numeric{iValue: iValue, dValue: dValue, sValue: sValue, isNil: isNull}
+}
+
+func NewNullNumeric() Numeric {
+  return &numeric{iValue: 0, dValue: 0.0, sValue: "", isNil: true}
+}
+
+func (p *numeric) Int64() int64 {
+  return p.iValue
+}
+
+func (p *numeric) Int32() int32 {
+  return int32(p.iValue)
+}
+
+func (p *numeric) Int16() int16 {
+  return int16(p.iValue)
+}
+
+func (p *numeric) Byte() byte {
+  return byte(p.iValue)
+}
+
+func (p *numeric) Int() int {
+  return int(p.iValue)
+}
+
+func (p *numeric) Float64() float64 {
+  return p.dValue
+}
+
+func (p *numeric) Float32() float32 {
+  return float32(p.dValue)
+}
+
+func (p *numeric) String() string {
+  return p.sValue
+}
+
+func (p *numeric) isNull() bool {
+  return p.isNil
+}
+
+func init() {
+  INFINITY = &numeric{iValue: 0, dValue: math.Inf(1), sValue: "Infinity", isNil: false}
+  NEGATIVE_INFINITY = &numeric{iValue: 0, dValue: math.Inf(-1), sValue: "-Infinity", isNil: false}
+  NAN = &numeric{iValue: 0, dValue: math.NaN(), sValue: "NaN", isNil: false}
+  ZERO = &numeric{iValue: 0, dValue: 0, sValue: "0", isNil: false}
+  NUMERIC_NULL = &numeric{iValue: 0, dValue: 0, sValue: "0", isNil: true}
+}
diff --git a/lib/go/thrift/tprocessor.go b/lib/go/thrift/tprocessor.go
new file mode 100644
index 0000000..d2bb5e4
--- /dev/null
+++ b/lib/go/thrift/tprocessor.go
@@ -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.
+ */
+
+package thrift
+
+/**
+ * A processor is a generic object which operates upon an input stream and
+ * writes to some output stream.
+ *
+ */
+type TProcessor interface {
+  Process(in, out TProtocol) (bool, TException)
+}
+
+type TProcessorFunction interface {
+  Process(seqId int32, in, out TProtocol) (bool, TException)
+}
diff --git a/lib/go/thrift/tprocessor_factory.go b/lib/go/thrift/tprocessor_factory.go
new file mode 100644
index 0000000..72681ab
--- /dev/null
+++ b/lib/go/thrift/tprocessor_factory.go
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+
+/**
+ * The default processor factory just returns a singleton
+ * instance.
+ */
+type TProcessorFactory interface {
+  GetProcessor(trans TTransport) TProcessor
+}
+
+type tProcessorFactory struct {
+  processor TProcessor
+}
+
+func NewTProcessorFactory(p TProcessor) TProcessorFactory {
+  return &tProcessorFactory{processor: p}
+}
+
+func (p *tProcessorFactory) GetProcessor(trans TTransport) TProcessor {
+  return p.processor
+}
+
+
+/**
+ * The default processor factory just returns a singleton
+ * instance.
+ */
+type TProcessorFunctionFactory interface {
+  GetProcessorFunction(trans TTransport) TProcessorFunction
+}
+
+type tProcessorFunctionFactory struct {
+  processor TProcessorFunction
+}
+
+func NewTProcessorFunctionFactory(p TProcessorFunction) TProcessorFunctionFactory {
+  return &tProcessorFunctionFactory{processor: p}
+}
+
+func (p *tProcessorFunctionFactory) GetProcessorFunction(trans TTransport) TProcessorFunction {
+  return p.processor
+}
diff --git a/lib/go/thrift/tprotocol.go b/lib/go/thrift/tprotocol.go
new file mode 100644
index 0000000..dcb27a8
--- /dev/null
+++ b/lib/go/thrift/tprotocol.go
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+
+const (
+  VERSION_MASK = 0xffff0000
+  VERSION_1    = 0x80010000
+)
+
+type EmptyInterface interface{}
+
+type TProtocol interface {
+  WriteMessageBegin(name string, typeId TMessageType, seqid int32) TProtocolException
+  WriteMessageEnd() TProtocolException
+  WriteStructBegin(name string) TProtocolException
+  WriteStructEnd() TProtocolException
+  WriteFieldBegin(name string, typeId TType, id int16) TProtocolException
+  WriteFieldEnd() TProtocolException
+  WriteFieldStop() TProtocolException
+  WriteMapBegin(keyType TType, valueType TType, size int) TProtocolException
+  WriteMapEnd() TProtocolException
+  WriteListBegin(elemType TType, size int) TProtocolException
+  WriteListEnd() TProtocolException
+  WriteSetBegin(elemType TType, size int) TProtocolException
+  WriteSetEnd() TProtocolException
+  WriteBool(value bool) TProtocolException
+  WriteByte(value byte) TProtocolException
+  WriteI16(value int16) TProtocolException
+  WriteI32(value int32) TProtocolException
+  WriteI64(value int64) TProtocolException
+  WriteDouble(value float64) TProtocolException
+  WriteString(value string) TProtocolException
+  WriteBinary(value []byte) TProtocolException
+
+  ReadMessageBegin() (name string, typeId TMessageType, seqid int32, err TProtocolException)
+  ReadMessageEnd() TProtocolException
+  ReadStructBegin() (name string, err TProtocolException)
+  ReadStructEnd() TProtocolException
+  ReadFieldBegin() (name string, typeId TType, id int16, err TProtocolException)
+  ReadFieldEnd() TProtocolException
+  ReadMapBegin() (keyType TType, valueType TType, size int, err TProtocolException)
+  ReadMapEnd() TProtocolException
+  ReadListBegin() (elemType TType, size int, err TProtocolException)
+  ReadListEnd() TProtocolException
+  ReadSetBegin() (elemType TType, size int, err TProtocolException)
+  ReadSetEnd() TProtocolException
+  ReadBool() (value bool, err TProtocolException)
+  ReadByte() (value byte, err TProtocolException)
+  ReadI16() (value int16, err TProtocolException)
+  ReadI32() (value int32, err TProtocolException)
+  ReadI64() (value int64, err TProtocolException)
+  ReadDouble() (value float64, err TProtocolException)
+  ReadString() (value string, err TProtocolException)
+  ReadBinary() (value []byte, err TProtocolException)
+
+  Skip(fieldType TType) (err TProtocolException)
+  Flush() (err TProtocolException)
+
+  Transport() TTransport
+}
+
+/**
+ * The maximum recursive depth the skip() function will traverse before
+ * throwing a TException.
+ */
+var (
+  MaxSkipDepth = 1<<31 - 1
+)
+
+/**
+ * Specifies the maximum recursive depth that the skip function will
+ * traverse before throwing a TException.  This is a global setting, so
+ * any call to skip in this JVM will enforce this value.
+ *
+ * @param depth  the maximum recursive depth.  A value of 2 would allow
+ *    the skip function to skip a structure or collection with basic children,
+ *    but it would not permit skipping a struct that had a field containing
+ *    a child struct.  A value of 1 would only allow skipping of simple
+ *    types and empty structs/collections.
+ */
+func SetMaxSkipDepth(depth int) {
+  MaxSkipDepth = depth
+}
+
+/**
+ * Skips over the next data element from the provided input TProtocol object.
+ *
+ * @param prot  the protocol object to read from
+ * @param type  the next value will be intepreted as this TType value.
+ */
+func SkipDefaultDepth(prot TProtocol, typeId TType) (err TProtocolException) {
+  return Skip(prot, typeId, MaxSkipDepth)
+}
+
+/**
+ * Skips over the next data element from the provided input TProtocol object.
+ *
+ * @param prot  the protocol object to read from
+ * @param type  the next value will be intepreted as this TType value.
+ * @param maxDepth  this function will only skip complex objects to this
+ *   recursive depth, to prevent Java stack overflow.
+ */
+func Skip(self TProtocol, fieldType TType, maxDepth int) (err TProtocolException) {
+  switch fieldType {
+  case STOP:
+    return
+  case BOOL:
+    _, err = self.ReadBool()
+    return
+  case BYTE:
+    _, err = self.ReadByte()
+    return
+  case I16:
+    _, err = self.ReadI16()
+    return
+  case I32:
+    _, err = self.ReadI32()
+    return
+  case I64:
+    _, err = self.ReadI64()
+    return
+  case DOUBLE:
+    _, err = self.ReadDouble()
+    return
+  case STRING:
+    _, err = self.ReadString()
+    return
+  case STRUCT:
+    {
+      _, err = self.ReadStructBegin()
+      if err != nil {
+        return
+      }
+      for {
+        _, typeId, _, _ := self.ReadFieldBegin()
+        if typeId == STOP {
+          break
+        }
+        Skip(self, typeId, maxDepth-1)
+        self.ReadFieldEnd()
+      }
+      return self.ReadStructEnd()
+    }
+  case MAP:
+    {
+      keyType, valueType, l, err := self.ReadMapBegin()
+      if err != nil {
+        return err
+      }
+      size := int(l)
+      for i := 0; i < size; i++ {
+        Skip(self, keyType, maxDepth-1)
+        self.Skip(valueType)
+      }
+      return self.ReadMapEnd()
+    }
+  case SET:
+    {
+      elemType, l, err := self.ReadSetBegin()
+      if err != nil {
+        return err
+      }
+      size := int(l)
+      for i := 0; i < size; i++ {
+        Skip(self, elemType, maxDepth-1)
+      }
+      return self.ReadSetEnd()
+    }
+  case LIST:
+    {
+      elemType, l, err := self.ReadListBegin()
+      if err != nil {
+        return err
+      }
+      size := int(l)
+      for i := 0; i < size; i++ {
+        Skip(self, elemType, maxDepth-1)
+      }
+      return self.ReadListEnd()
+    }
+  }
+  return nil
+}
diff --git a/lib/go/thrift/tprotocol_exception.go b/lib/go/thrift/tprotocol_exception.go
new file mode 100644
index 0000000..2dac97e
--- /dev/null
+++ b/lib/go/thrift/tprotocol_exception.go
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package thrift
+
+import (
+  "encoding/base64"
+  "os"
+)
+
+/**
+ * Protocol exceptions.
+ *
+ */
+type TProtocolException interface {
+  TException
+  TypeId() int
+}
+
+const (
+  UNKNOWN_PROTOCOL_EXCEPTION = 0
+  INVALID_DATA               = 1
+  NEGATIVE_SIZE              = 2
+  SIZE_LIMIT                 = 3
+  BAD_VERSION                = 4
+  NOT_IMPLEMENTED            = 5
+)
+
+type tProtocolException struct {
+  typeId  int
+  message string
+}
+
+func (p *tProtocolException) TypeId() int {
+  return p.typeId
+}
+
+func (p *tProtocolException) String() string {
+  return p.message
+}
+
+func NewTProtocolExceptionDefault() TProtocolException {
+  return NewTProtocolExceptionDefaultType(UNKNOWN_PROTOCOL_EXCEPTION)
+}
+
+func NewTProtocolExceptionDefaultType(t int) TProtocolException {
+  return NewTProtocolException(t, "")
+}
+
+func NewTProtocolExceptionDefaultString(m string) TProtocolException {
+  return NewTProtocolException(UNKNOWN_PROTOCOL_EXCEPTION, m)
+}
+
+func NewTProtocolException(t int, m string) TProtocolException {
+  return &tProtocolException{typeId: t, message: m}
+}
+
+func NewTProtocolExceptionReadField(fieldId int, fieldName string, structName string, e TProtocolException) TProtocolException {
+  t := e.TypeId()
+  if t == UNKNOWN_PROTOCOL_EXCEPTION {
+    t = INVALID_DATA
+  }
+  return NewTProtocolException(t, "Unable to read field "+string(fieldId)+" ("+fieldName+") in "+structName+" due to: "+e.String())
+}
+
+func NewTProtocolExceptionWriteField(fieldId int, fieldName string, structName string, e TProtocolException) TProtocolException {
+  t := e.TypeId()
+  if t == UNKNOWN_PROTOCOL_EXCEPTION {
+    t = INVALID_DATA
+  }
+  return NewTProtocolException(t, "Unable to write field "+string(fieldId)+" ("+fieldName+") in "+structName+" due to: "+e.String())
+}
+
+func NewTProtocolExceptionReadStruct(structName string, e TProtocolException) TProtocolException {
+  t := e.TypeId()
+  if t == UNKNOWN_PROTOCOL_EXCEPTION {
+    t = INVALID_DATA
+  }
+  return NewTProtocolException(t, "Unable to read struct "+structName+" due to: "+e.String())
+}
+
+func NewTProtocolExceptionWriteStruct(structName string, e TProtocolException) TProtocolException {
+  t := e.TypeId()
+  if t == UNKNOWN_PROTOCOL_EXCEPTION {
+    t = INVALID_DATA
+  }
+  return NewTProtocolException(t, "Unable to write struct "+structName+" due to: "+e.String())
+}
+
+func NewTProtocolExceptionFromOsError(e os.Error) TProtocolException {
+  if e == nil {
+    return nil
+  }
+  if t, ok := e.(TProtocolException); ok {
+    return t
+  }
+  if te, ok := e.(TTransportException); ok {
+    return NewTProtocolExceptionFromTransportException(te)
+  }
+  if _, ok := e.(base64.CorruptInputError); ok {
+    return NewTProtocolException(INVALID_DATA, e.String())
+  }
+  return NewTProtocolExceptionDefaultString(e.String())
+}
+
+func NewTProtocolExceptionFromTransportException(e TTransportException) TProtocolException {
+  if e == nil {
+    return nil
+  }
+  if t, ok := e.(TProtocolException); ok {
+    return t
+  }
+  return NewTProtocolExceptionDefaultString(e.String())
+}
diff --git a/lib/go/thrift/tprotocol_factory.go b/lib/go/thrift/tprotocol_factory.go
new file mode 100644
index 0000000..2eed2c2
--- /dev/null
+++ b/lib/go/thrift/tprotocol_factory.go
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+/**
+ * Factory interface for constructing protocol instances.
+ *
+ */
+type TProtocolFactory interface {
+  GetProtocol(trans TTransport) TProtocol
+}
diff --git a/lib/go/thrift/tprotocol_test.go b/lib/go/thrift/tprotocol_test.go
new file mode 100644
index 0000000..22d6ad6
--- /dev/null
+++ b/lib/go/thrift/tprotocol_test.go
@@ -0,0 +1,1817 @@
+/*
+ * 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.
+ */
+
+package thrift_test
+
+import (
+  . "thrift"
+  "testing"
+  "http"
+  "math"
+  "net"
+  "io"
+  "os"
+  "bytes"
+  "fmt"
+)
+
+const PROTOCOL_BINARY_DATA_SIZE = 155
+
+var (
+  data           string // test data for writing
+  protocol_bdata []byte // test data for writing; same as data
+  BOOL_VALUES    []bool
+  BYTE_VALUES    []byte
+  INT16_VALUES   []int16
+  INT32_VALUES   []int32
+  INT64_VALUES   []int64
+  DOUBLE_VALUES  []float64
+  STRING_VALUES  []string
+)
+
+
+func init() {
+  protocol_bdata = make([]byte, PROTOCOL_BINARY_DATA_SIZE)
+  for i := 0; i < PROTOCOL_BINARY_DATA_SIZE; i++ {
+    protocol_bdata[i] = byte((i + 'a') % 255)
+  }
+  data = string(protocol_bdata)
+  BOOL_VALUES = []bool{false, true, false, false, true}
+  BYTE_VALUES = []byte{117, 0, 1, 32, 127, 128, 255}
+  INT16_VALUES = []int16{459, 0, 1, -1, -128, 127, 32767, -32768}
+  INT32_VALUES = []int32{459, 0, 1, -1, -128, 127, 32767, 2147483647, -2147483535}
+  INT64_VALUES = []int64{459, 0, 1, -1, -128, 127, 32767, 2147483647, -2147483535, 34359738481, -35184372088719, -9223372036854775808, 9223372036854775807}
+  DOUBLE_VALUES = []float64{459.3, 0.0, -1.0, 1.0, 0.5, 0.3333, 3.14159, 1.537e-38, 1.673e25, 6.02214179e23, -6.02214179e23, INFINITY.Float64(), NEGATIVE_INFINITY.Float64(), NAN.Float64()}
+  STRING_VALUES = []string{"", "a", "st[uf]f", "st,u:ff with spaces", "stuff\twith\nescape\\characters'...\"lots{of}fun</xml>"}
+}
+
+type HTTPEchoServer struct{}
+
+func (p *HTTPEchoServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+  w.WriteHeader(http.StatusOK)
+  io.Copy(w, req.Body)
+}
+
+func HttpClientSetupForTest(t *testing.T) (net.Listener, net.Addr) {
+  addr, err := FindAvailableTCPServerPort(40000)
+  if err != nil {
+    t.Fatalf("Unable to find available tcp port addr: %s", err)
+  }
+  l, err := net.Listen(addr.Network(), addr.String())
+  if err != nil {
+    t.Fatalf("Unable to setup tcp listener on %s: %s", addr.String(), err)
+  }
+  go http.Serve(l, &HTTPEchoServer{})
+  return l, addr
+}
+
+
+func ReadWriteProtocolTest(t *testing.T, protocolFactory TProtocolFactory) {
+  buf := bytes.NewBuffer(make([]byte, 0, 1024))
+  l, addr := HttpClientSetupForTest(t)
+  transports := []TTransportFactory{
+    NewTMemoryBufferTransportFactory(1024),
+    NewTIOStreamTransportFactory(buf, buf, true),
+    NewTFramedTransportFactory(NewTMemoryBufferTransportFactory(1024)),
+    NewTHttpPostClientTransportFactory("http://" + addr.String()),
+  }
+  for _, tf := range transports {
+    trans := tf.GetTransport(nil)
+    p := protocolFactory.GetProtocol(trans)
+    ReadWriteBool(t, p, trans)
+    trans.Close()
+  }
+  for _, tf := range transports {
+    trans := tf.GetTransport(nil)
+    p := protocolFactory.GetProtocol(trans)
+    ReadWriteByte(t, p, trans)
+    trans.Close()
+  }
+  for _, tf := range transports {
+    trans := tf.GetTransport(nil)
+    p := protocolFactory.GetProtocol(trans)
+    ReadWriteI16(t, p, trans)
+    trans.Close()
+  }
+  for _, tf := range transports {
+    trans := tf.GetTransport(nil)
+    p := protocolFactory.GetProtocol(trans)
+    ReadWriteI32(t, p, trans)
+    trans.Close()
+  }
+  for _, tf := range transports {
+    trans := tf.GetTransport(nil)
+    p := protocolFactory.GetProtocol(trans)
+    ReadWriteI64(t, p, trans)
+    trans.Close()
+  }
+  for _, tf := range transports {
+    trans := tf.GetTransport(nil)
+    p := protocolFactory.GetProtocol(trans)
+    ReadWriteDouble(t, p, trans)
+    trans.Close()
+  }
+  for _, tf := range transports {
+    trans := tf.GetTransport(nil)
+    p := protocolFactory.GetProtocol(trans)
+    ReadWriteString(t, p, trans)
+    trans.Close()
+  }
+  for _, tf := range transports {
+    trans := tf.GetTransport(nil)
+    p := protocolFactory.GetProtocol(trans)
+    ReadWriteBinary(t, p, trans)
+    trans.Close()
+  }
+  for _, tf := range transports {
+    trans := tf.GetTransport(nil)
+    p := protocolFactory.GetProtocol(trans)
+    ReadWriteWork(t, p, trans)
+    trans.Close()
+  }
+  for _, tf := range transports {
+    trans := tf.GetTransport(nil)
+    p := protocolFactory.GetProtocol(trans)
+    ReadWriteCalculate(t, p, trans)
+    trans.Close()
+  }
+
+  // this test doesn't work in all cases due to EOF issues between
+  // buffer read and buffer write when using the same bufio for both
+  //for _, tf := range transports {
+  //  trans := tf.GetTransport(nil)
+  //  p := GetProtocol(trans);
+  //  ReadWriteI64(t, p, trans);
+  //  ReadWriteDouble(t, p, trans);
+  //  ReadWriteBinary(t, p, trans);
+  //  ReadWriteByte(t, p, trans);
+  //  trans.Close()
+  //}
+
+  l.Close()
+}
+
+func ReadWriteBool(t *testing.T, p TProtocol, trans TTransport) {
+  thetype := TType(BOOL)
+  thelen := len(BOOL_VALUES)
+  err := p.WriteListBegin(thetype, thelen)
+  if err != nil {
+    t.Errorf("%s: %T %T %q Error writing list begin: %q", "ReadWriteBool", p, trans, err, thetype)
+  }
+  for k, v := range BOOL_VALUES {
+    err = p.WriteBool(v)
+    if err != nil {
+      t.Errorf("%s: %T %T %q Error writing bool in list at index %d: %q", "ReadWriteBool", p, trans, err, k, v)
+    }
+  }
+  p.WriteListEnd()
+  if err != nil {
+    t.Errorf("%s: %T %T %q Error writing list end: %q", "ReadWriteBool", p, trans, err, BOOL_VALUES)
+  }
+  p.Flush()
+  thetype2, thelen2, err := p.ReadListBegin()
+  if err != nil {
+    t.Errorf("%s: %T %T %q Error reading list: %q", "ReadWriteBool", p, trans, err, BOOL_VALUES)
+  }
+  _, ok := p.(*TSimpleJSONProtocol)
+  if !ok {
+    if thetype != thetype2 {
+      t.Errorf("%s: %T %T type %s != type %s", "ReadWriteBool", p, trans, thetype, thetype2)
+    }
+    if thelen != thelen2 {
+      t.Errorf("%s: %T %T len %s != len %s", "ReadWriteBool", p, trans, thelen, thelen2)
+    }
+  }
+  for k, v := range BOOL_VALUES {
+    value, err := p.ReadBool()
+    if err != nil {
+      t.Errorf("%s: %T %T %q Error reading bool at index %d: %q", "ReadWriteBool", p, trans, err, k, v)
+    }
+    if v != value {
+      t.Errorf("%s: index %d %q %q %q != %q", "ReadWriteBool", k, p, trans, v, value)
+    }
+  }
+  err = p.ReadListEnd()
+  if err != nil {
+    t.Errorf("%s: %T %T Unable to read list end: %q", "ReadWriteBool", p, trans, err)
+  }
+}
+
+func ReadWriteByte(t *testing.T, p TProtocol, trans TTransport) {
+  thetype := TType(BYTE)
+  thelen := len(BYTE_VALUES)
+  err := p.WriteListBegin(thetype, thelen)
+  if err != nil {
+    t.Errorf("%s: %T %T %q Error writing list begin: %q", "ReadWriteByte", p, trans, err, thetype)
+  }
+  for k, v := range BYTE_VALUES {
+    err = p.WriteByte(v)
+    if err != nil {
+      t.Errorf("%s: %T %T %q Error writing byte in list at index %d: %q", "ReadWriteByte", p, trans, err, k, v)
+    }
+  }
+  err = p.WriteListEnd()
+  if err != nil {
+    t.Errorf("%s: %T %T %q Error writing list end: %q", "ReadWriteByte", p, trans, err, BYTE_VALUES)
+  }
+  err = p.Flush()
+  if err != nil {
+    t.Errorf("%s: %T %T %q Error flushing list of bytes: %q", "ReadWriteByte", p, trans, err, BYTE_VALUES)
+  }
+  thetype2, thelen2, err := p.ReadListBegin()
+  if err != nil {
+    t.Errorf("%s: %T %T %q Error reading list: %q", "ReadWriteByte", p, trans, err, BYTE_VALUES)
+  }
+  _, ok := p.(*TSimpleJSONProtocol)
+  if !ok {
+    if thetype != thetype2 {
+      t.Errorf("%s: %T %T type %s != type %s", "ReadWriteByte", p, trans, thetype, thetype2)
+    }
+    if thelen != thelen2 {
+      t.Errorf("%s: %T %T len %s != len %s", "ReadWriteByte", p, trans, thelen, thelen2)
+    }
+  }
+  for k, v := range BYTE_VALUES {
+    value, err := p.ReadByte()
+    if err != nil {
+      t.Errorf("%s: %T %T %q Error reading byte at index %d: %q", "ReadWriteByte", p, trans, err, k, v)
+    }
+    if v != value {
+      t.Errorf("%s: %T %T %d != %d", "ReadWriteByte", p, trans, v, value)
+    }
+  }
+  err = p.ReadListEnd()
+  if err != nil {
+    t.Errorf("%s: %T %T Unable to read list end: %q", "ReadWriteByte", p, trans, err)
+  }
+}
+
+func ReadWriteI16(t *testing.T, p TProtocol, trans TTransport) {
+  thetype := TType(I16)
+  thelen := len(INT16_VALUES)
+  p.WriteListBegin(thetype, thelen)
+  for _, v := range INT16_VALUES {
+    p.WriteI16(v)
+  }
+  p.WriteListEnd()
+  p.Flush()
+  thetype2, thelen2, err := p.ReadListBegin()
+  if err != nil {
+    t.Errorf("%s: %T %T %q Error reading list: %q", "ReadWriteI16", p, trans, err, INT16_VALUES)
+  }
+  _, ok := p.(*TSimpleJSONProtocol)
+  if !ok {
+    if thetype != thetype2 {
+      t.Errorf("%s: %T %T type %s != type %s", "ReadWriteI16", p, trans, thetype, thetype2)
+    }
+    if thelen != thelen2 {
+      t.Errorf("%s: %T %T len %s != len %s", "ReadWriteI16", p, trans, thelen, thelen2)
+    }
+  }
+  for k, v := range INT16_VALUES {
+    value, err := p.ReadI16()
+    if err != nil {
+      t.Errorf("%s: %T %T %q Error reading int16 at index %d: %q", "ReadWriteI16", p, trans, err, k, v)
+    }
+    if v != value {
+      t.Errorf("%s: %T %T %d != %d", "ReadWriteI16", p, trans, v, value)
+    }
+  }
+  err = p.ReadListEnd()
+  if err != nil {
+    t.Errorf("%s: %T %T Unable to read list end: %q", "ReadWriteI16", p, trans, err)
+  }
+}
+
+func ReadWriteI32(t *testing.T, p TProtocol, trans TTransport) {
+  thetype := TType(I32)
+  thelen := len(INT32_VALUES)
+  p.WriteListBegin(thetype, thelen)
+  for _, v := range INT32_VALUES {
+    p.WriteI32(v)
+  }
+  p.WriteListEnd()
+  p.Flush()
+  thetype2, thelen2, err := p.ReadListBegin()
+  if err != nil {
+    t.Errorf("%s: %T %T %q Error reading list: %q", "ReadWriteI32", p, trans, err, INT32_VALUES)
+  }
+  _, ok := p.(*TSimpleJSONProtocol)
+  if !ok {
+    if thetype != thetype2 {
+      t.Errorf("%s: %T %T type %s != type %s", "ReadWriteI32", p, trans, thetype, thetype2)
+    }
+    if thelen != thelen2 {
+      t.Errorf("%s: %T %T len %s != len %s", "ReadWriteI32", p, trans, thelen, thelen2)
+    }
+  }
+  for k, v := range INT32_VALUES {
+    value, err := p.ReadI32()
+    if err != nil {
+      t.Errorf("%s: %T %T %q Error reading int32 at index %d: %q", "ReadWriteI32", p, trans, err, k, v)
+    }
+    if v != value {
+      t.Errorf("%s: %T %T %d != %d", "ReadWriteI32", p, trans, v, value)
+    }
+  }
+  if err != nil {
+    t.Errorf("%s: %T %T Unable to read list end: %q", "ReadWriteI32", p, trans, err)
+  }
+}
+
+func ReadWriteI64(t *testing.T, p TProtocol, trans TTransport) {
+  thetype := TType(I64)
+  thelen := len(INT64_VALUES)
+  p.WriteListBegin(thetype, thelen)
+  for _, v := range INT64_VALUES {
+    p.WriteI64(v)
+  }
+  p.WriteListEnd()
+  p.Flush()
+  thetype2, thelen2, err := p.ReadListBegin()
+  if err != nil {
+    t.Errorf("%s: %T %T %q Error reading list: %q", "ReadWriteI64", p, trans, err, INT64_VALUES)
+  }
+  _, ok := p.(*TSimpleJSONProtocol)
+  if !ok {
+    if thetype != thetype2 {
+      t.Errorf("%s: %T %T type %s != type %s", "ReadWriteI64", p, trans, thetype, thetype2)
+    }
+    if thelen != thelen2 {
+      t.Errorf("%s: %T %T len %s != len %s", "ReadWriteI64", p, trans, thelen, thelen2)
+    }
+  }
+  for k, v := range INT64_VALUES {
+    value, err := p.ReadI64()
+    if err != nil {
+      t.Errorf("%s: %T %T %q Error reading int64 at index %d: %q", "ReadWriteI64", p, trans, err, k, v)
+    }
+    if v != value {
+      t.Errorf("%s: %T %T %q != %q", "ReadWriteI64", p, trans, v, value)
+    }
+  }
+  if err != nil {
+    t.Errorf("%s: %T %T Unable to read list end: %q", "ReadWriteI64", p, trans, err)
+  }
+}
+
+func ReadWriteDouble(t *testing.T, p TProtocol, trans TTransport) {
+  thetype := TType(DOUBLE)
+  thelen := len(DOUBLE_VALUES)
+  p.WriteListBegin(thetype, thelen)
+  for _, v := range DOUBLE_VALUES {
+    p.WriteDouble(v)
+  }
+  p.WriteListEnd()
+  p.Flush()
+  wrotebuffer := ""
+  if memtrans, ok := trans.(*TMemoryBuffer); ok {
+    wrotebuffer = memtrans.String()
+  }
+  thetype2, thelen2, err := p.ReadListBegin()
+  if err != nil {
+    t.Errorf("%s: %T %T %q Error reading list: %q, wrote: %v", "ReadWriteDouble", p, trans, err, DOUBLE_VALUES, wrotebuffer)
+  }
+  if thetype != thetype2 {
+    t.Errorf("%s: %T %T type %s != type %s", "ReadWriteDouble", p, trans, thetype, thetype2)
+  }
+  if thelen != thelen2 {
+    t.Errorf("%s: %T %T len %s != len %s", "ReadWriteDouble", p, trans, thelen, thelen2)
+  }
+  for k, v := range DOUBLE_VALUES {
+    value, err := p.ReadDouble()
+    if err != nil {
+      t.Errorf("%s: %T %T %q Error reading double at index %d: %q", "ReadWriteDouble", p, trans, err, k, v)
+    }
+    if math.IsNaN(v) {
+      if !math.IsNaN(value) {
+        t.Errorf("%s: %T %T math.IsNaN(%q) != math.IsNaN(%q)", "ReadWriteDouble", p, trans, v, value)
+      }
+    } else if v != value {
+      t.Errorf("%s: %T %T %v != %q", "ReadWriteDouble", p, trans, v, value)
+    }
+  }
+  err = p.ReadListEnd()
+  if err != nil {
+    t.Errorf("%s: %T %T Unable to read list end: %q", "ReadWriteDouble", p, trans, err)
+  }
+}
+
+func ReadWriteString(t *testing.T, p TProtocol, trans TTransport) {
+  thetype := TType(STRING)
+  thelen := len(STRING_VALUES)
+  p.WriteListBegin(thetype, thelen)
+  for _, v := range STRING_VALUES {
+    p.WriteString(v)
+  }
+  p.WriteListEnd()
+  p.Flush()
+  thetype2, thelen2, err := p.ReadListBegin()
+  if err != nil {
+    t.Errorf("%s: %T %T %q Error reading list: %q", "ReadWriteString", p, trans, err, STRING_VALUES)
+  }
+  _, ok := p.(*TSimpleJSONProtocol)
+  if !ok {
+    if thetype != thetype2 {
+      t.Errorf("%s: %T %T type %s != type %s", "ReadWriteString", p, trans, thetype, thetype2)
+    }
+    if thelen != thelen2 {
+      t.Errorf("%s: %T %T len %s != len %s", "ReadWriteString", p, trans, thelen, thelen2)
+    }
+  }
+  for k, v := range STRING_VALUES {
+    value, err := p.ReadString()
+    if err != nil {
+      t.Errorf("%s: %T %T %q Error reading string at index %d: %q", "ReadWriteString", p, trans, err, k, v)
+    }
+    if v != value {
+      t.Errorf("%s: %T %T %d != %d", "ReadWriteString", p, trans, v, value)
+    }
+  }
+  if err != nil {
+    t.Errorf("%s: %T %T Unable to read list end: %q", "ReadWriteString", p, trans, err)
+  }
+}
+
+
+func ReadWriteBinary(t *testing.T, p TProtocol, trans TTransport) {
+  v := protocol_bdata
+  p.WriteBinary(v)
+  p.Flush()
+  value, err := p.ReadBinary()
+  if err != nil {
+    t.Errorf("%s: %T %T Unable to read binary: %s", "ReadWriteBinary", p, trans, err.String())
+  }
+  if len(v) != len(value) {
+    t.Errorf("%s: %T %T len(v) != len(value)... %d != %d", "ReadWriteBinary", p, trans, len(v), len(value))
+  } else {
+    for i := 0; i < len(v); i++ {
+      if v[i] != value[i] {
+        t.Errorf("%s: %T %T %s != %s", "ReadWriteBinary", p, trans, v, value)
+      }
+    }
+  }
+}
+
+
+func ReadWriteWork(t *testing.T, p TProtocol, trans TTransport) {
+  thetype := "struct"
+  orig := NewWork()
+  orig.Num1 = 25
+  orig.Num2 = 102
+  orig.Op = ADD
+  orig.Comment = "Add: 25 + 102"
+  return
+  if e := orig.Write(p); e != nil {
+    t.Fatalf("Unable to write %s value %#v due to error: %s", thetype, orig, e.String())
+  }
+  read := NewWork()
+  e := read.Read(p)
+  if e != nil {
+    t.Fatalf("Unable to read %s due to error: %s", thetype, e.String())
+  }
+  if !orig.Equals(read) {
+    t.Fatalf("Original Write != Read: %#v != %#v ", orig, read)
+  }
+}
+
+
+func ReadWriteCalculate(t *testing.T, p TProtocol, trans TTransport) {
+  messageName := "calculate"
+  logid := int32(12)
+  seqId := int32(35)
+  w := NewWork()
+  w.Num1 = 25
+  w.Num2 = 102
+  w.Op = ADD
+  w.Comment = "Add: 25 + 102"
+
+  args31 := NewCalculateArgs()
+  args31.Logid = logid
+  args31.W = w
+  p.WriteMessageBegin(messageName, CALL, seqId)
+  if err := args31.Write(p); err != nil {
+    t.Fatalf("%s: %T %T Unable to write message: %s", messageName, p, trans, err.String())
+  }
+  p.WriteMessageEnd()
+  p.Transport().Flush()
+
+  name, ttype, seqid, err1 := p.ReadMessageBegin()
+  if err1 != nil {
+    t.Fatalf("%s: %T %T Unable to read message begin: %s", messageName, p, trans, err1.String())
+  }
+  if name != messageName {
+    t.Errorf("%s: %T %T Expected message named \"%s\", but was: \"%s\"", messageName, p, trans, messageName, name)
+  }
+  if ttype != CALL {
+    t.Errorf("%s: %T %T Expected message type \"%s\", but was: \"%s\"", messageName, p, trans, CALL, ttype)
+  }
+  if seqid != seqId {
+    t.Errorf("%s: %T %T Expected message type \"%s\", but was: \"%s\"", messageName, p, trans, seqId, seqid)
+  }
+  calcArgs := NewCalculateArgs()
+  err2 := calcArgs.Read(p)
+  if !args31.Equals(calcArgs) {
+    //cmp1, _ := args31.W.CompareTo(calcArgs.W)
+    cmp2, ok := args31.CompareTo(calcArgs)
+    t.Errorf("%s: %T %T Calculate args not as expected, %T vs %T, cmp: %#v, ok: %#v, equals: %#v", messageName, p, trans, args31, calcArgs, cmp2, ok, args31.Equals(calcArgs))
+  }
+  if err2 != nil {
+    t.Fatalf("%s: %T %T Unable to read message end: %s", messageName, p, trans, err2.String())
+  }
+  err3 := p.ReadMessageEnd()
+  if err3 != nil {
+    t.Fatalf("%s: %T %T Unable to read message end: %s", messageName, p, trans, err3.String())
+  }
+}
+
+
+/**
+ *You can define enums, which are just 32 bit integers. Values are optional
+ *and start at 1 if not supplied, C style again.
+ */
+type Operation int
+
+const (
+  ADD      Operation = 1
+  SUBTRACT Operation = 2
+  MULTIPLY Operation = 3
+  DIVIDE   Operation = 4
+)
+
+func (p Operation) String() string {
+  switch p {
+  case ADD:
+    return "ADD"
+  case SUBTRACT:
+    return "SUBTRACT"
+  case MULTIPLY:
+    return "MULTIPLY"
+  case DIVIDE:
+    return "DIVIDE"
+  }
+  return ""
+}
+
+func FromOperationString(s string) Operation {
+  switch s {
+  case "ADD":
+    return ADD
+  case "SUBTRACT":
+    return SUBTRACT
+  case "MULTIPLY":
+    return MULTIPLY
+  case "DIVIDE":
+    return DIVIDE
+  }
+  return Operation(-10000)
+}
+
+func (p Operation) Value() int {
+  return int(p)
+}
+
+func (p Operation) IsEnum() bool {
+  return true
+}
+
+/**
+ *Thrift lets you do typedefs to get pretty names for your types. Standard
+ *C style here.
+ */
+type MyInteger int32
+
+const INT32CONSTANT = 9853
+
+var MAPCONSTANT TMap
+/**
+ * Structs are the basic complex data structures. They are comprised of fields
+ * which each have an integer identifier, a type, a symbolic name, and an
+ * optional default value.
+ * 
+ * Fields can be declared "optional", which ensures they will not be included
+ * in the serialized output if they aren't set.  Note that this requires some
+ * manual management in some languages.
+ * 
+ * Attributes:
+ *  - Num1
+ *  - Num2
+ *  - Op
+ *  - Comment
+ */
+type Work struct {
+  TStruct
+  _       interface{} "num1"    // nil # 0
+  Num1    int32       "num1"    // 1
+  Num2    int32       "num2"    // 2
+  Op      Operation   "op"      // 3
+  Comment string      "comment" // 4
+}
+
+func NewWork() *Work {
+  output := &Work{
+    TStruct: NewTStruct("Work", []TField{
+      NewTField("num1", I32, 1),
+      NewTField("num2", I32, 2),
+      NewTField("op", I32, 3),
+      NewTField("comment", STRING, 4),
+    }),
+  }
+  {
+    output.Num1 = 0
+  }
+  return output
+}
+
+func (p *Work) Read(iprot TProtocol) (err TProtocolException) {
+  _, err = iprot.ReadStructBegin()
+  if err != nil {
+    return NewTProtocolExceptionReadStruct(p.ThriftName(), err)
+  }
+  for {
+    fieldName, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()
+    if fieldId < 0 {
+      fieldId = int16(p.FieldIdFromFieldName(fieldName))
+    } else if fieldName == "" {
+      fieldName = p.FieldNameFromFieldId(int(fieldId))
+    }
+    if fieldTypeId == GENERIC {
+      fieldTypeId = p.FieldFromFieldId(int(fieldId)).TypeId()
+    }
+    if err != nil {
+      return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+    }
+    if fieldTypeId == STOP {
+      break
+    }
+    if fieldId == 1 || fieldName == "num1" {
+      if fieldTypeId == I32 {
+        err = p.ReadField1(iprot)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      } else if fieldTypeId == VOID {
+        err = iprot.Skip(fieldTypeId)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      } else {
+        err = p.ReadField1(iprot)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      }
+    } else if fieldId == 2 || fieldName == "num2" {
+      if fieldTypeId == I32 {
+        err = p.ReadField2(iprot)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      } else if fieldTypeId == VOID {
+        err = iprot.Skip(fieldTypeId)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      } else {
+        err = p.ReadField2(iprot)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      }
+    } else if fieldId == 3 || fieldName == "op" {
+      if fieldTypeId == I32 {
+        err = p.ReadField3(iprot)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      } else if fieldTypeId == VOID {
+        err = iprot.Skip(fieldTypeId)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      } else {
+        err = p.ReadField3(iprot)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      }
+    } else if fieldId == 4 || fieldName == "comment" {
+      if fieldTypeId == STRING {
+        err = p.ReadField4(iprot)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      } else if fieldTypeId == VOID {
+        err = iprot.Skip(fieldTypeId)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      } else {
+        err = p.ReadField4(iprot)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      }
+    } else {
+      err = iprot.Skip(fieldTypeId)
+      if err != nil {
+        return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+      }
+    }
+    err = iprot.ReadFieldEnd()
+    if err != nil {
+      return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+    }
+  }
+  err = iprot.ReadStructEnd()
+  if err != nil {
+    return NewTProtocolExceptionReadStruct(p.ThriftName(), err)
+  }
+  return err
+}
+
+func (p *Work) ReadField1(iprot TProtocol) (err TProtocolException) {
+  v4, err5 := iprot.ReadI32()
+  if err5 != nil {
+    return NewTProtocolExceptionReadField(1, "num1", p.ThriftName(), err5)
+  }
+  p.Num1 = v4
+  return err
+}
+
+func (p *Work) ReadFieldNum1(iprot TProtocol) TProtocolException {
+  return p.ReadField1(iprot)
+}
+
+func (p *Work) ReadField2(iprot TProtocol) (err TProtocolException) {
+  v6, err7 := iprot.ReadI32()
+  if err7 != nil {
+    return NewTProtocolExceptionReadField(2, "num2", p.ThriftName(), err7)
+  }
+  p.Num2 = v6
+  return err
+}
+
+func (p *Work) ReadFieldNum2(iprot TProtocol) TProtocolException {
+  return p.ReadField2(iprot)
+}
+
+func (p *Work) ReadField3(iprot TProtocol) (err TProtocolException) {
+  v8, err9 := iprot.ReadI32()
+  if err9 != nil {
+    return NewTProtocolExceptionReadField(3, "op", p.ThriftName(), err9)
+  }
+  p.Op = Operation(v8)
+  return err
+}
+
+func (p *Work) ReadFieldOp(iprot TProtocol) TProtocolException {
+  return p.ReadField3(iprot)
+}
+
+func (p *Work) ReadField4(iprot TProtocol) (err TProtocolException) {
+  v10, err11 := iprot.ReadString()
+  if err11 != nil {
+    return NewTProtocolExceptionReadField(4, "comment", p.ThriftName(), err11)
+  }
+  p.Comment = v10
+  return err
+}
+
+func (p *Work) ReadFieldComment(iprot TProtocol) TProtocolException {
+  return p.ReadField4(iprot)
+}
+
+func (p *Work) Write(oprot TProtocol) (err TProtocolException) {
+  err = oprot.WriteStructBegin("Work")
+  if err != nil {
+    return NewTProtocolExceptionWriteStruct(p.ThriftName(), err)
+  }
+  err = p.WriteField1(oprot)
+  if err != nil {
+    return err
+  }
+  err = p.WriteField2(oprot)
+  if err != nil {
+    return err
+  }
+  err = p.WriteField3(oprot)
+  if err != nil {
+    return err
+  }
+  err = p.WriteField4(oprot)
+  if err != nil {
+    return err
+  }
+  err = oprot.WriteFieldStop()
+  if err != nil {
+    return NewTProtocolExceptionWriteField(-1, "STOP", p.ThriftName(), err)
+  }
+  err = oprot.WriteStructEnd()
+  if err != nil {
+    return NewTProtocolExceptionWriteStruct(p.ThriftName(), err)
+  }
+  return err
+}
+
+func (p *Work) WriteField1(oprot TProtocol) (err TProtocolException) {
+  err = oprot.WriteFieldBegin("num1", I32, 1)
+  if err != nil {
+    return NewTProtocolExceptionWriteField(1, "num1", p.ThriftName(), err)
+  }
+  err = oprot.WriteI32(int32(p.Num1))
+  if err != nil {
+    return NewTProtocolExceptionWriteField(1, "num1", p.ThriftName(), err)
+  }
+  err = oprot.WriteFieldEnd()
+  if err != nil {
+    return NewTProtocolExceptionWriteField(1, "num1", p.ThriftName(), err)
+  }
+  return err
+}
+
+func (p *Work) WriteFieldNum1(oprot TProtocol) TProtocolException {
+  return p.WriteField1(oprot)
+}
+
+func (p *Work) WriteField2(oprot TProtocol) (err TProtocolException) {
+  err = oprot.WriteFieldBegin("num2", I32, 2)
+  if err != nil {
+    return NewTProtocolExceptionWriteField(2, "num2", p.ThriftName(), err)
+  }
+  err = oprot.WriteI32(int32(p.Num2))
+  if err != nil {
+    return NewTProtocolExceptionWriteField(2, "num2", p.ThriftName(), err)
+  }
+  err = oprot.WriteFieldEnd()
+  if err != nil {
+    return NewTProtocolExceptionWriteField(2, "num2", p.ThriftName(), err)
+  }
+  return err
+}
+
+func (p *Work) WriteFieldNum2(oprot TProtocol) TProtocolException {
+  return p.WriteField2(oprot)
+}
+
+func (p *Work) WriteField3(oprot TProtocol) (err TProtocolException) {
+  err = oprot.WriteFieldBegin("op", I32, 3)
+  if err != nil {
+    return NewTProtocolExceptionWriteField(3, "op", p.ThriftName(), err)
+  }
+  err = oprot.WriteI32(int32(p.Op))
+  if err != nil {
+    return NewTProtocolExceptionWriteField(3, "op", p.ThriftName(), err)
+  }
+  err = oprot.WriteFieldEnd()
+  if err != nil {
+    return NewTProtocolExceptionWriteField(3, "op", p.ThriftName(), err)
+  }
+  return err
+}
+
+func (p *Work) WriteFieldOp(oprot TProtocol) TProtocolException {
+  return p.WriteField3(oprot)
+}
+
+func (p *Work) WriteField4(oprot TProtocol) (err TProtocolException) {
+  err = oprot.WriteFieldBegin("comment", STRING, 4)
+  if err != nil {
+    return NewTProtocolExceptionWriteField(4, "comment", p.ThriftName(), err)
+  }
+  err = oprot.WriteString(string(p.Comment))
+  if err != nil {
+    return NewTProtocolExceptionWriteField(4, "comment", p.ThriftName(), err)
+  }
+  err = oprot.WriteFieldEnd()
+  if err != nil {
+    return NewTProtocolExceptionWriteField(4, "comment", p.ThriftName(), err)
+  }
+  return err
+}
+
+func (p *Work) WriteFieldComment(oprot TProtocol) TProtocolException {
+  return p.WriteField4(oprot)
+}
+
+func (p *Work) TStructName() string {
+  return "Work"
+}
+
+func (p *Work) ThriftName() string {
+  return "Work"
+}
+
+func (p *Work) String() string {
+  if p == nil {
+    return "<nil>"
+  }
+  return fmt.Sprintf("Work(%+v)", *p)
+}
+
+func (p *Work) CompareTo(other interface{}) (int, bool) {
+  if other == nil {
+    return 1, true
+  }
+  data, ok := other.(*Work)
+  if !ok {
+    return 0, false
+  }
+  if p.Num1 != data.Num1 {
+    if p.Num1 < data.Num1 {
+      return -1, true
+    }
+    return 1, true
+  }
+  if p.Num2 != data.Num2 {
+    if p.Num2 < data.Num2 {
+      return -1, true
+    }
+    return 1, true
+  }
+  if p.Op != data.Op {
+    if p.Op < data.Op {
+      return -1, true
+    }
+    return 1, true
+  }
+  if p.Comment != data.Comment {
+    if p.Comment < data.Comment {
+      return -1, true
+    }
+    return 1, true
+  }
+  return 0, true
+}
+
+func (p *Work) AttributeByFieldId(id int) interface{} {
+  switch id {
+  default:
+    return nil
+  case 1:
+    return p.Num1
+  case 2:
+    return p.Num2
+  case 3:
+    return p.Op
+  case 4:
+    return p.Comment
+  }
+  return nil
+}
+
+func (p *Work) TStructFields() TFieldContainer {
+  return NewTFieldContainer([]TField{
+    NewTField("num1", I32, 1),
+    NewTField("num2", I32, 2),
+    NewTField("op", I32, 3),
+    NewTField("comment", STRING, 4),
+  })
+}
+
+
+type ICalculator interface {
+  /**
+   * Parameters:
+   *  - Key
+   */
+  Calculate(logid int32, w *Work) (retval30 int32, ouch *InvalidOperation, err os.Error)
+}
+
+type CalculatorClient struct {
+  Transport       TTransport
+  ProtocolFactory TProtocolFactory
+  InputProtocol   TProtocol
+  OutputProtocol  TProtocol
+  SeqId           int32
+}
+
+func NewCalculatorClientFactory(t TTransport, f TProtocolFactory) *CalculatorClient {
+  return &CalculatorClient{Transport: t,
+    ProtocolFactory: f,
+    InputProtocol:   f.GetProtocol(t),
+    OutputProtocol:  f.GetProtocol(t),
+    SeqId:           0,
+  }
+}
+
+func NewCalculatorClientProtocol(t TTransport, iprot TProtocol, oprot TProtocol) *CalculatorClient {
+  return &CalculatorClient{Transport: t,
+    ProtocolFactory: nil,
+    InputProtocol:   iprot,
+    OutputProtocol:  oprot,
+    SeqId:           0,
+  }
+}
+
+
+/**
+ * Parameters:
+ *  - Logid
+ *  - W
+ */
+func (p *CalculatorClient) Calculate(logid int32, w *Work) (retval30 int32, ouch *InvalidOperation, err os.Error) {
+  err = p.SendCalculate(logid, w)
+  if err != nil {
+    return
+  }
+  return p.RecvCalculate()
+}
+
+func (p *CalculatorClient) SendCalculate(logid int32, w *Work) (err os.Error) {
+  oprot := p.OutputProtocol
+  if oprot != nil {
+    oprot = p.ProtocolFactory.GetProtocol(p.Transport)
+    p.OutputProtocol = oprot
+  }
+  oprot.WriteMessageBegin("calculate", CALL, p.SeqId)
+  args31 := NewCalculateArgs()
+  args31.Logid = logid
+  args31.W = w
+  err = args31.Write(oprot)
+  oprot.WriteMessageEnd()
+  oprot.Transport().Flush()
+  return
+}
+
+
+func (p *CalculatorClient) RecvCalculate() (value int32, ouch *InvalidOperation, err os.Error) {
+  iprot := p.InputProtocol
+  if iprot == nil {
+    iprot = p.ProtocolFactory.GetProtocol(p.Transport)
+    p.InputProtocol = iprot
+  }
+  _, mTypeId, _, err := iprot.ReadMessageBegin()
+  if err != nil {
+    return
+  }
+  if mTypeId == EXCEPTION {
+    error33 := NewTApplicationExceptionDefault()
+    error34, err := error33.Read(iprot)
+    if err != nil {
+      return
+    }
+    if err = iprot.ReadMessageEnd(); err != nil {
+      return
+    }
+    err = error34
+    return
+  }
+  result32 := NewCalculateResult()
+  err = result32.Read(iprot)
+  iprot.ReadMessageEnd()
+  value = result32.Success
+  if result32.Ouch != nil {
+    ouch = result32.Ouch
+  }
+  return
+}
+
+
+/**
+ * Attributes:
+ *  - Logid
+ *  - W
+ */
+type CalculateArgs struct {
+  TStruct
+  _     interface{} "logid" // nil # 0
+  Logid int32       "logid" // 1
+  W     *Work       "w"     // 2
+}
+
+func NewCalculateArgs() *CalculateArgs {
+  output := &CalculateArgs{
+    TStruct: NewTStruct("calculate_args", []TField{
+      NewTField("logid", I32, 1),
+      NewTField("w", STRUCT, 2),
+    }),
+  }
+  {
+  }
+  return output
+}
+
+func (p *CalculateArgs) Read(iprot TProtocol) (err TProtocolException) {
+  _, err = iprot.ReadStructBegin()
+  if err != nil {
+    return NewTProtocolExceptionReadStruct(p.ThriftName(), err)
+  }
+  for {
+    fieldName, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()
+    if fieldId < 0 {
+      fieldId = int16(p.FieldIdFromFieldName(fieldName))
+    } else if fieldName == "" {
+      fieldName = p.FieldNameFromFieldId(int(fieldId))
+    }
+    if fieldTypeId == GENERIC {
+      fieldTypeId = p.FieldFromFieldId(int(fieldId)).TypeId()
+    }
+    if err != nil {
+      return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+    }
+    if fieldTypeId == STOP {
+      break
+    }
+    if fieldId == 1 || fieldName == "logid" {
+      if fieldTypeId == I32 {
+        err = p.ReadField1(iprot)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      } else if fieldTypeId == VOID {
+        err = iprot.Skip(fieldTypeId)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      } else {
+        err = p.ReadField1(iprot)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      }
+    } else if fieldId == 2 || fieldName == "w" {
+      if fieldTypeId == STRUCT {
+        err = p.ReadField2(iprot)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      } else if fieldTypeId == VOID {
+        err = iprot.Skip(fieldTypeId)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      } else {
+        err = p.ReadField2(iprot)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      }
+    } else {
+      err = iprot.Skip(fieldTypeId)
+      if err != nil {
+        return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+      }
+    }
+    err = iprot.ReadFieldEnd()
+    if err != nil {
+      return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+    }
+  }
+  err = iprot.ReadStructEnd()
+  if err != nil {
+    return NewTProtocolExceptionReadStruct(p.ThriftName(), err)
+  }
+  return err
+}
+
+func (p *CalculateArgs) ReadField1(iprot TProtocol) (err TProtocolException) {
+  v47, err48 := iprot.ReadI32()
+  if err48 != nil {
+    return NewTProtocolExceptionReadField(1, "logid", p.ThriftName(), err48)
+  }
+  p.Logid = v47
+  return err
+}
+
+func (p *CalculateArgs) ReadFieldLogid(iprot TProtocol) TProtocolException {
+  return p.ReadField1(iprot)
+}
+
+func (p *CalculateArgs) ReadField2(iprot TProtocol) (err TProtocolException) {
+  p.W = NewWork()
+  err51 := p.W.Read(iprot)
+  if err51 != nil {
+    return NewTProtocolExceptionReadStruct("p.WWork", err51)
+  }
+  return err
+}
+
+func (p *CalculateArgs) ReadFieldW(iprot TProtocol) TProtocolException {
+  return p.ReadField2(iprot)
+}
+
+func (p *CalculateArgs) Write(oprot TProtocol) (err TProtocolException) {
+  err = oprot.WriteStructBegin("calculate_args")
+  if err != nil {
+    return NewTProtocolExceptionWriteStruct(p.ThriftName(), err)
+  }
+  err = p.WriteField1(oprot)
+  if err != nil {
+    return err
+  }
+  err = p.WriteField2(oprot)
+  if err != nil {
+    return err
+  }
+  err = oprot.WriteFieldStop()
+  if err != nil {
+    return NewTProtocolExceptionWriteField(-1, "STOP", p.ThriftName(), err)
+  }
+  err = oprot.WriteStructEnd()
+  if err != nil {
+    return NewTProtocolExceptionWriteStruct(p.ThriftName(), err)
+  }
+  return err
+}
+
+func (p *CalculateArgs) WriteField1(oprot TProtocol) (err TProtocolException) {
+  err = oprot.WriteFieldBegin("logid", I32, 1)
+  if err != nil {
+    return NewTProtocolExceptionWriteField(1, "logid", p.ThriftName(), err)
+  }
+  err = oprot.WriteI32(int32(p.Logid))
+  if err != nil {
+    return NewTProtocolExceptionWriteField(1, "logid", p.ThriftName(), err)
+  }
+  err = oprot.WriteFieldEnd()
+  if err != nil {
+    return NewTProtocolExceptionWriteField(1, "logid", p.ThriftName(), err)
+  }
+  return err
+}
+
+func (p *CalculateArgs) WriteFieldLogid(oprot TProtocol) TProtocolException {
+  return p.WriteField1(oprot)
+}
+
+func (p *CalculateArgs) WriteField2(oprot TProtocol) (err TProtocolException) {
+  if p.W != nil {
+    err = oprot.WriteFieldBegin("w", STRUCT, 2)
+    if err != nil {
+      return NewTProtocolExceptionWriteField(2, "w", p.ThriftName(), err)
+    }
+    err = p.W.Write(oprot)
+    if err != nil {
+      return NewTProtocolExceptionWriteStruct("Work", err)
+    }
+    err = oprot.WriteFieldEnd()
+    if err != nil {
+      return NewTProtocolExceptionWriteField(2, "w", p.ThriftName(), err)
+    }
+  }
+  return err
+}
+
+func (p *CalculateArgs) WriteFieldW(oprot TProtocol) TProtocolException {
+  return p.WriteField2(oprot)
+}
+
+func (p *CalculateArgs) TStructName() string {
+  return "CalculateArgs"
+}
+
+func (p *CalculateArgs) ThriftName() string {
+  return "calculate_args"
+}
+
+func (p *CalculateArgs) String() string {
+  if p == nil {
+    return "<nil>"
+  }
+  return fmt.Sprintf("CalculateArgs(%+v)", *p)
+}
+
+func (p *CalculateArgs) CompareTo(other interface{}) (int, bool) {
+  if other == nil {
+    return 1, true
+  }
+  data, ok := other.(*CalculateArgs)
+  if !ok {
+    return 0, false
+  }
+  if p.Logid != data.Logid {
+    if p.Logid < data.Logid {
+      return -1, true
+    }
+    return 1, true
+  }
+  if cmp, ok := p.W.CompareTo(data.W); !ok || cmp != 0 {
+    return cmp, ok
+  }
+  return 0, true
+}
+
+func (p *CalculateArgs) AttributeByFieldId(id int) interface{} {
+  switch id {
+  default:
+    return nil
+  case 1:
+    return p.Logid
+  case 2:
+    return p.W
+  }
+  return nil
+}
+
+func (p *CalculateArgs) TStructFields() TFieldContainer {
+  return NewTFieldContainer([]TField{
+    NewTField("logid", I32, 1),
+    NewTField("w", STRUCT, 2),
+  })
+}
+
+/**
+ * Attributes:
+ *  - Success
+ *  - Ouch
+ */
+type CalculateResult struct {
+  TStruct
+  Success int32             "success" // 0
+  Ouch    *InvalidOperation "ouch"    // 1
+}
+
+func NewCalculateResult() *CalculateResult {
+  output := &CalculateResult{
+    TStruct: NewTStruct("calculate_result", []TField{
+      NewTField("success", I32, 0),
+      NewTField("ouch", STRUCT, 1),
+    }),
+  }
+  {
+  }
+  return output
+}
+
+func (p *CalculateResult) Read(iprot TProtocol) (err TProtocolException) {
+  _, err = iprot.ReadStructBegin()
+  if err != nil {
+    return NewTProtocolExceptionReadStruct(p.ThriftName(), err)
+  }
+  for {
+    fieldName, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()
+    if fieldId < 0 {
+      fieldId = int16(p.FieldIdFromFieldName(fieldName))
+    } else if fieldName == "" {
+      fieldName = p.FieldNameFromFieldId(int(fieldId))
+    }
+    if fieldTypeId == GENERIC {
+      fieldTypeId = p.FieldFromFieldId(int(fieldId)).TypeId()
+    }
+    if err != nil {
+      return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+    }
+    if fieldTypeId == STOP {
+      break
+    }
+    if fieldId == 0 || fieldName == "success" {
+      if fieldTypeId == I32 {
+        err = p.ReadField0(iprot)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      } else if fieldTypeId == VOID {
+        err = iprot.Skip(fieldTypeId)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      } else {
+        err = p.ReadField0(iprot)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      }
+    } else if fieldId == 1 || fieldName == "ouch" {
+      if fieldTypeId == STRUCT {
+        err = p.ReadField1(iprot)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      } else if fieldTypeId == VOID {
+        err = iprot.Skip(fieldTypeId)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      } else {
+        err = p.ReadField1(iprot)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      }
+    } else {
+      err = iprot.Skip(fieldTypeId)
+      if err != nil {
+        return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+      }
+    }
+    err = iprot.ReadFieldEnd()
+    if err != nil {
+      return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+    }
+  }
+  err = iprot.ReadStructEnd()
+  if err != nil {
+    return NewTProtocolExceptionReadStruct(p.ThriftName(), err)
+  }
+  return err
+}
+
+func (p *CalculateResult) ReadField0(iprot TProtocol) (err TProtocolException) {
+  v52, err53 := iprot.ReadI32()
+  if err53 != nil {
+    return NewTProtocolExceptionReadField(0, "success", p.ThriftName(), err53)
+  }
+  p.Success = v52
+  return err
+}
+
+func (p *CalculateResult) ReadFieldSuccess(iprot TProtocol) TProtocolException {
+  return p.ReadField0(iprot)
+}
+
+func (p *CalculateResult) ReadField1(iprot TProtocol) (err TProtocolException) {
+  p.Ouch = NewInvalidOperation()
+  err56 := p.Ouch.Read(iprot)
+  if err56 != nil {
+    return NewTProtocolExceptionReadStruct("p.OuchInvalidOperation", err56)
+  }
+  return err
+}
+
+func (p *CalculateResult) ReadFieldOuch(iprot TProtocol) TProtocolException {
+  return p.ReadField1(iprot)
+}
+
+func (p *CalculateResult) Write(oprot TProtocol) (err TProtocolException) {
+  err = oprot.WriteStructBegin("calculate_result")
+  if err != nil {
+    return NewTProtocolExceptionWriteStruct(p.ThriftName(), err)
+  }
+  err = p.WriteField0(oprot)
+  if err != nil {
+    return err
+  }
+  err = p.WriteField1(oprot)
+  if err != nil {
+    return err
+  }
+  err = oprot.WriteFieldStop()
+  if err != nil {
+    return NewTProtocolExceptionWriteField(-1, "STOP", p.ThriftName(), err)
+  }
+  err = oprot.WriteStructEnd()
+  if err != nil {
+    return NewTProtocolExceptionWriteStruct(p.ThriftName(), err)
+  }
+  return err
+}
+
+func (p *CalculateResult) WriteField0(oprot TProtocol) (err TProtocolException) {
+  err = oprot.WriteFieldBegin("success", I32, 0)
+  if err != nil {
+    return NewTProtocolExceptionWriteField(0, "success", p.ThriftName(), err)
+  }
+  err = oprot.WriteI32(int32(p.Success))
+  if err != nil {
+    return NewTProtocolExceptionWriteField(0, "success", p.ThriftName(), err)
+  }
+  err = oprot.WriteFieldEnd()
+  if err != nil {
+    return NewTProtocolExceptionWriteField(0, "success", p.ThriftName(), err)
+  }
+  return err
+}
+
+func (p *CalculateResult) WriteFieldSuccess(oprot TProtocol) TProtocolException {
+  return p.WriteField0(oprot)
+}
+
+func (p *CalculateResult) WriteField1(oprot TProtocol) (err TProtocolException) {
+  if p.Ouch != nil {
+    err = oprot.WriteFieldBegin("ouch", STRUCT, 1)
+    if err != nil {
+      return NewTProtocolExceptionWriteField(1, "ouch", p.ThriftName(), err)
+    }
+    err = p.Ouch.Write(oprot)
+    if err != nil {
+      return NewTProtocolExceptionWriteStruct("InvalidOperation", err)
+    }
+    err = oprot.WriteFieldEnd()
+    if err != nil {
+      return NewTProtocolExceptionWriteField(1, "ouch", p.ThriftName(), err)
+    }
+  }
+  return err
+}
+
+func (p *CalculateResult) WriteFieldOuch(oprot TProtocol) TProtocolException {
+  return p.WriteField1(oprot)
+}
+
+func (p *CalculateResult) TStructName() string {
+  return "CalculateResult"
+}
+
+func (p *CalculateResult) ThriftName() string {
+  return "calculate_result"
+}
+
+func (p *CalculateResult) String() string {
+  if p == nil {
+    return "<nil>"
+  }
+  return fmt.Sprintf("CalculateResult(%+v)", *p)
+}
+
+func (p *CalculateResult) CompareTo(other interface{}) (int, bool) {
+  if other == nil {
+    return 1, true
+  }
+  data, ok := other.(*CalculateResult)
+  if !ok {
+    return 0, false
+  }
+  if p.Success != data.Success {
+    if p.Success < data.Success {
+      return -1, true
+    }
+    return 1, true
+  }
+  if cmp, ok := p.Ouch.CompareTo(data.Ouch); !ok || cmp != 0 {
+    return cmp, ok
+  }
+  return 0, true
+}
+
+func (p *CalculateResult) AttributeByFieldId(id int) interface{} {
+  switch id {
+  default:
+    return nil
+  case 0:
+    return p.Success
+  case 1:
+    return p.Ouch
+  }
+  return nil
+}
+
+func (p *CalculateResult) TStructFields() TFieldContainer {
+  return NewTFieldContainer([]TField{
+    NewTField("success", I32, 0),
+    NewTField("ouch", STRUCT, 1),
+  })
+}
+
+
+/**
+ * Structs can also be exceptions, if they are nasty.
+ * 
+ * Attributes:
+ *  - What
+ *  - Why
+ */
+type InvalidOperation struct {
+  TStruct
+  _    interface{} "what" // nil # 0
+  What int32       "what" // 1
+  Why  string      "why"  // 2
+}
+
+func NewInvalidOperation() *InvalidOperation {
+  output := &InvalidOperation{
+    TStruct: NewTStruct("InvalidOperation", []TField{
+      NewTField("what", I32, 1),
+      NewTField("why", STRING, 2),
+    }),
+  }
+  {
+  }
+  return output
+}
+
+func (p *InvalidOperation) Read(iprot TProtocol) (err TProtocolException) {
+  _, err = iprot.ReadStructBegin()
+  if err != nil {
+    return NewTProtocolExceptionReadStruct(p.ThriftName(), err)
+  }
+  for {
+    fieldName, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()
+    if fieldId < 0 {
+      fieldId = int16(p.FieldIdFromFieldName(fieldName))
+    } else if fieldName == "" {
+      fieldName = p.FieldNameFromFieldId(int(fieldId))
+    }
+    if fieldTypeId == GENERIC {
+      fieldTypeId = p.FieldFromFieldId(int(fieldId)).TypeId()
+    }
+    if err != nil {
+      return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+    }
+    if fieldTypeId == STOP {
+      break
+    }
+    if fieldId == 1 || fieldName == "what" {
+      if fieldTypeId == I32 {
+        err = p.ReadField1(iprot)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      } else if fieldTypeId == VOID {
+        err = iprot.Skip(fieldTypeId)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      } else {
+        err = p.ReadField1(iprot)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      }
+    } else if fieldId == 2 || fieldName == "why" {
+      if fieldTypeId == STRING {
+        err = p.ReadField2(iprot)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      } else if fieldTypeId == VOID {
+        err = iprot.Skip(fieldTypeId)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      } else {
+        err = p.ReadField2(iprot)
+        if err != nil {
+          return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+        }
+      }
+    } else {
+      err = iprot.Skip(fieldTypeId)
+      if err != nil {
+        return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+      }
+    }
+    err = iprot.ReadFieldEnd()
+    if err != nil {
+      return NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)
+    }
+  }
+  err = iprot.ReadStructEnd()
+  if err != nil {
+    return NewTProtocolExceptionReadStruct(p.ThriftName(), err)
+  }
+  return err
+}
+
+func (p *InvalidOperation) ReadField1(iprot TProtocol) (err TProtocolException) {
+  v12, err13 := iprot.ReadI32()
+  if err13 != nil {
+    return NewTProtocolExceptionReadField(1, "what", p.ThriftName(), err13)
+  }
+  p.What = v12
+  return err
+}
+
+func (p *InvalidOperation) ReadFieldWhat(iprot TProtocol) TProtocolException {
+  return p.ReadField1(iprot)
+}
+
+func (p *InvalidOperation) ReadField2(iprot TProtocol) (err TProtocolException) {
+  v14, err15 := iprot.ReadString()
+  if err15 != nil {
+    return NewTProtocolExceptionReadField(2, "why", p.ThriftName(), err15)
+  }
+  p.Why = v14
+  return err
+}
+
+func (p *InvalidOperation) ReadFieldWhy(iprot TProtocol) TProtocolException {
+  return p.ReadField2(iprot)
+}
+
+func (p *InvalidOperation) Write(oprot TProtocol) (err TProtocolException) {
+  err = oprot.WriteStructBegin("InvalidOperation")
+  if err != nil {
+    return NewTProtocolExceptionWriteStruct(p.ThriftName(), err)
+  }
+  err = p.WriteField1(oprot)
+  if err != nil {
+    return err
+  }
+  err = p.WriteField2(oprot)
+  if err != nil {
+    return err
+  }
+  err = oprot.WriteFieldStop()
+  if err != nil {
+    return NewTProtocolExceptionWriteField(-1, "STOP", p.ThriftName(), err)
+  }
+  err = oprot.WriteStructEnd()
+  if err != nil {
+    return NewTProtocolExceptionWriteStruct(p.ThriftName(), err)
+  }
+  return err
+}
+
+func (p *InvalidOperation) WriteField1(oprot TProtocol) (err TProtocolException) {
+  err = oprot.WriteFieldBegin("what", I32, 1)
+  if err != nil {
+    return NewTProtocolExceptionWriteField(1, "what", p.ThriftName(), err)
+  }
+  err = oprot.WriteI32(int32(p.What))
+  if err != nil {
+    return NewTProtocolExceptionWriteField(1, "what", p.ThriftName(), err)
+  }
+  err = oprot.WriteFieldEnd()
+  if err != nil {
+    return NewTProtocolExceptionWriteField(1, "what", p.ThriftName(), err)
+  }
+  return err
+}
+
+func (p *InvalidOperation) WriteFieldWhat(oprot TProtocol) TProtocolException {
+  return p.WriteField1(oprot)
+}
+
+func (p *InvalidOperation) WriteField2(oprot TProtocol) (err TProtocolException) {
+  err = oprot.WriteFieldBegin("why", STRING, 2)
+  if err != nil {
+    return NewTProtocolExceptionWriteField(2, "why", p.ThriftName(), err)
+  }
+  err = oprot.WriteString(string(p.Why))
+  if err != nil {
+    return NewTProtocolExceptionWriteField(2, "why", p.ThriftName(), err)
+  }
+  err = oprot.WriteFieldEnd()
+  if err != nil {
+    return NewTProtocolExceptionWriteField(2, "why", p.ThriftName(), err)
+  }
+  return err
+}
+
+func (p *InvalidOperation) WriteFieldWhy(oprot TProtocol) TProtocolException {
+  return p.WriteField2(oprot)
+}
+
+func (p *InvalidOperation) TStructName() string {
+  return "InvalidOperation"
+}
+
+func (p *InvalidOperation) ThriftName() string {
+  return "InvalidOperation"
+}
+
+func (p *InvalidOperation) String() string {
+  if p == nil {
+    return "<nil>"
+  }
+  return fmt.Sprintf("InvalidOperation(%+v)", *p)
+}
+
+func (p *InvalidOperation) CompareTo(other interface{}) (int, bool) {
+  if other == nil {
+    return 1, true
+  }
+  data, ok := other.(*InvalidOperation)
+  if !ok {
+    return 0, false
+  }
+  if p.What != data.What {
+    if p.What < data.What {
+      return -1, true
+    }
+    return 1, true
+  }
+  if p.Why != data.Why {
+    if p.Why < data.Why {
+      return -1, true
+    }
+    return 1, true
+  }
+  return 0, true
+}
+
+func (p *InvalidOperation) AttributeByFieldId(id int) interface{} {
+  switch id {
+  default:
+    return nil
+  case 1:
+    return p.What
+  case 2:
+    return p.Why
+  }
+  return nil
+}
+
+func (p *InvalidOperation) TStructFields() TFieldContainer {
+  return NewTFieldContainer([]TField{
+    NewTField("what", I32, 1),
+    NewTField("why", STRING, 2),
+  })
+}
diff --git a/lib/go/thrift/tserver.go b/lib/go/thrift/tserver.go
new file mode 100644
index 0000000..6bc3167
--- /dev/null
+++ b/lib/go/thrift/tserver.go
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "os"
+)
+
+type TServer interface {
+  /**
+   * Core processor
+   */
+  ProcessorFactory() TProcessorFactory
+  /**
+   * Server transport
+   */
+  ServerTransport() TServerTransport
+  /**
+   * Input Transport Factory
+   */
+  InputTransportFactory() TTransportFactory
+  /**
+   * Output Transport Factory
+   */
+  OutputTransportFactory() TTransportFactory
+  /**
+   * Input Protocol Factory
+   */
+  InputProtocolFactory() TProtocolFactory
+  /**
+   * Output Protocol Factory
+   */
+  OutputProtocolFactory() TProtocolFactory
+
+  /**
+   * The run method fires up the server and gets things going.
+   */
+  Serve() os.Error
+  /**
+   * Stop the server. This is optional on a per-implementation basis. Not
+   * all servers are required to be cleanly stoppable.
+   */
+  Stop() os.Error
+}
diff --git a/lib/go/thrift/tserver_socket.go b/lib/go/thrift/tserver_socket.go
new file mode 100644
index 0000000..dc3e748
--- /dev/null
+++ b/lib/go/thrift/tserver_socket.go
@@ -0,0 +1,194 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "net"
+  "os"
+)
+
+
+type TServerSocket struct {
+  /**
+   * Underlying socket conection object
+   */
+  conn net.Conn
+  /**
+   * Underlying socket conection object
+   */
+  listener net.Listener
+
+  /**
+   * Address to listen on
+   */
+  addr net.Addr
+
+  /**
+   * Client timeout in nanoseconds
+   */
+  nsecClientTimeout int64
+}
+
+type TServerSocketTransportFactory struct {
+  addr              net.Addr
+  nsecClientTimeout int64
+}
+
+func (p *TServerSocketTransportFactory) GetTransport(trans TTransport) TTransport {
+  if trans != nil {
+    t, ok := trans.(*TServerSocket)
+    if ok && t.addr != nil {
+      s, _ := NewTServerSocketAddrTimeout(t.addr, t.nsecClientTimeout)
+      return s
+    }
+  }
+  s, _ := NewTServerSocketAddrTimeout(p.addr, p.nsecClientTimeout)
+  return s
+}
+
+func NewTServerSocketTransportFactory(addr net.Addr, nsecClientTimeout int64) *TServerSocketTransportFactory {
+  return &TServerSocketTransportFactory{addr: addr, nsecClientTimeout: nsecClientTimeout}
+}
+
+func NewTServerSocketConn(conn net.Conn) *TServerSocket {
+  return NewTServerSocketConnTimeout(conn, 0)
+}
+
+func NewTServerSocketConnTimeout(conn net.Conn, nsecClientTimeout int64) *TServerSocket {
+  v := &TServerSocket{conn: conn, addr: conn.LocalAddr(), nsecClientTimeout: nsecClientTimeout}
+  conn.SetTimeout(nsecClientTimeout)
+  return v
+}
+
+func NewTServerSocketAddr(addr net.Addr) (*TServerSocket, TTransportException) {
+  return NewTServerSocketAddrTimeout(addr, 0)
+}
+
+func NewTServerSocketAddrTimeout(addr net.Addr, nsecClientTimeout int64) (*TServerSocket, TTransportException) {
+  s := &TServerSocket{addr: addr, nsecClientTimeout: nsecClientTimeout}
+  return s, nil
+}
+
+func (p *TServerSocket) Listen() (err os.Error) {
+  if p.listener == nil {
+    if p.listener, err = net.Listen("tcp", p.addr.String()); err != nil {
+      return err
+    }
+  }
+  return nil
+}
+
+func (p *TServerSocket) Accept() (TTransport, os.Error) {
+  if p.listener == nil {
+    if err := p.Listen(); err != nil {
+      return nil, NewTTransportExceptionFromOsError(err)
+    }
+    if p.listener == nil {
+      return nil, NewTTransportException(NOT_OPEN, "No underlying server socket")
+    }
+  }
+  conn, err := p.listener.Accept()
+  if err != nil {
+    return nil, NewTTransportExceptionFromOsError(err)
+  }
+  conn.SetTimeout(p.nsecClientTimeout)
+  return NewTSocketConn(conn)
+}
+
+/**
+ * Checks whether the socket is connected.
+ */
+func (p *TServerSocket) IsOpen() bool {
+  return p.listener != nil
+}
+
+/**
+ * Connects the socket, creating a new socket object if necessary.
+ */
+func (p *TServerSocket) Open() os.Error {
+  if !p.IsOpen() {
+    l, err := net.Listen(p.addr.Network(), p.addr.String())
+    if err != nil {
+      return err
+    }
+    p.listener = l
+    return nil
+  }
+  return NewTTransportException(ALREADY_OPEN, "Server socket already open")
+}
+
+/**
+ * Perform a nonblocking read into buffer.
+ */
+func (p *TServerSocket) Read(buf []byte) (int, os.Error) {
+  return 0, NewTTransportException(UNKNOWN_TRANSPORT_EXCEPTION, "TServerSocket.Read([]byte) is not implemented")
+}
+
+func (p *TServerSocket) ReadAll(buf []byte) (int, os.Error) {
+  return ReadAllTransport(p, buf)
+}
+
+/**
+ * Perform a nonblocking write of the data in buffer;
+ */
+func (p *TServerSocket) Write(buf []byte) (int, os.Error) {
+  return 0, NewTTransportException(UNKNOWN_TRANSPORT_EXCEPTION, "TServerSocket.Write([]byte) is not implemented")
+}
+
+/**
+ * Flushes the underlying output stream if not null.
+ */
+func (p *TServerSocket) Flush() os.Error {
+  return NewTTransportException(UNKNOWN_TRANSPORT_EXCEPTION, "TServerSocket.Flush() is not implemented")
+}
+
+func (p *TServerSocket) Addr() net.Addr {
+  return p.addr
+}
+
+func (p *TServerSocket) Peek() bool {
+  return p.IsOpen()
+}
+
+/**
+ * Closes the socket.
+ */
+func (p *TServerSocket) Close() (err os.Error) {
+  if p.IsOpen() {
+    err := p.listener.Close()
+    if err != nil {
+      return NewTTransportExceptionFromOsError(err)
+    }
+    p.listener = nil
+  }
+  if p.conn != nil {
+    err := p.conn.Close()
+    if err != nil {
+      return NewTTransportExceptionFromOsError(err)
+    }
+    p.conn = nil
+  }
+  return nil
+}
+
+func (p *TServerSocket) Interrupt() os.Error {
+  // TODO(pomack) fix Interrupt as it is probably not right
+  return NewTTransportExceptionFromOsError(p.Close())
+}
diff --git a/lib/go/thrift/tserver_test.go b/lib/go/thrift/tserver_test.go
new file mode 100644
index 0000000..3cbe879
--- /dev/null
+++ b/lib/go/thrift/tserver_test.go
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+package thrift_test
+
+import (
+  "testing"
+)
+
+func TestNothing(t *testing.T) {
+
+}
diff --git a/lib/go/thrift/tserver_transport.go b/lib/go/thrift/tserver_transport.go
new file mode 100644
index 0000000..ef3a462
--- /dev/null
+++ b/lib/go/thrift/tserver_transport.go
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import "os"
+
+/**
+ * Server transport. Object which provides client transports.
+ *
+ */
+type TServerTransport interface {
+  Listen() os.Error
+  Accept() (TTransport, os.Error)
+  Close() os.Error
+
+  /**
+   * Optional method implementation. This signals to the server transport
+   * that it should break out of any accept() or listen() that it is currently
+   * blocked on. This method, if implemented, MUST be thread safe, as it may
+   * be called from a different thread context than the other TServerTransport
+   * methods.
+   */
+  Interrupt() os.Error
+}
diff --git a/lib/go/thrift/tset.go b/lib/go/thrift/tset.go
new file mode 100644
index 0000000..f868109
--- /dev/null
+++ b/lib/go/thrift/tset.go
@@ -0,0 +1,207 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "container/list"
+)
+
+/**
+ * Helper class that encapsulates set metadata.
+ *
+ */
+type TSet interface {
+  TContainer
+  ElemType() TType
+  Add(data interface{})
+  Remove(data interface{})
+  Less(other interface{}) bool
+  Front() *list.Element
+  Back() *list.Element
+  Values() []interface{}
+}
+
+type tSet struct {
+  elemType TType
+  size     int
+  l        *list.List
+}
+
+func NewTSet(t TType, s int) TSet {
+  return &tSet{elemType: t, size: s, l: list.New()}
+}
+
+func NewTSetDefault() TSet {
+  return NewTSet(STOP, 0)
+}
+
+func (p *tSet) ElemType() TType {
+  return p.elemType
+}
+
+func (p *tSet) Front() *list.Element {
+  return p.l.Front()
+}
+
+func (p *tSet) Back() *list.Element {
+  return p.l.Back()
+}
+
+func (p *tSet) Len() int {
+  if p.l.Len() != 0 {
+    return p.l.Len()
+  }
+  return p.size
+}
+
+func (p *tSet) Contains(data interface{}) bool {
+  return p.find(data) != nil
+}
+
+func (p *tSet) Add(other interface{}) {
+  if data, ok := p.elemType.CoerceData(other); ok {
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      if cmp, ok := p.elemType.Compare(data, elem.Value); ok && cmp >= 0 {
+        if cmp > 0 {
+          p.l.InsertBefore(data, elem)
+        }
+        return
+      }
+    }
+  }
+}
+
+func (p *tSet) Remove(data interface{}) {
+  elem := p.find(data)
+  if elem != nil {
+    p.l.Remove(elem)
+  }
+}
+
+func (p *tSet) Less(other interface{}) bool {
+  cmp, ok := p.CompareTo(other)
+  return ok && cmp > 0
+}
+
+func (p *tSet) Equals(other interface{}) bool {
+  c, cok := p.CompareTo(other)
+  return cok && c == 0
+}
+
+func (p *tSet) CompareTo(other interface{}) (int, bool) {
+  return TType(SET).Compare(p, other)
+}
+
+func (p *tSet) find(data interface{}) *list.Element {
+  if data == nil {
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      if elem.Value == nil {
+        return elem
+      }
+    }
+    return nil
+  }
+  data, ok := p.elemType.CoerceData(data)
+  if data == nil || !ok {
+    return nil
+  }
+  if p.elemType.IsBaseType() || p.elemType.IsEnum() {
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      if data == elem.Value {
+        return elem
+      }
+    }
+    return nil
+  }
+  if cmp, ok := data.(EqualsOtherInterface); ok {
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      if cmp.Equals(elem.Value) {
+        return elem
+      }
+    }
+    return nil
+  }
+  switch p.elemType {
+  case MAP:
+    if cmp, ok := data.(EqualsMap); ok {
+      for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+        v := elem.Value
+        if v == nil {
+          continue
+        }
+        if cmp.Equals(v.(TMap)) {
+          return elem
+        }
+      }
+      return nil
+    }
+  case SET:
+    if cmp, ok := data.(EqualsSet); ok {
+      for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+        v := elem.Value
+        if v == nil {
+          continue
+        }
+        if cmp.Equals(v.(TSet)) {
+          return elem
+        }
+      }
+      return nil
+    }
+  case LIST:
+    if cmp, ok := data.(EqualsList); ok {
+      for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+        v := elem.Value
+        if v == nil {
+          continue
+        }
+        if cmp.Equals(v.(TList)) {
+          return elem
+        }
+      }
+      return nil
+    }
+  case STRUCT:
+    if cmp, ok := data.(EqualsStruct); ok {
+      for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+        v := elem.Value
+        if v == nil {
+          continue
+        }
+        if cmp.Equals(v.(TStruct)) {
+          return elem
+        }
+      }
+      return nil
+    }
+  }
+  return nil
+}
+
+func (p *tSet) Values() []interface{} {
+  size := p.l.Len()
+  values := make([]interface{}, size, size)
+  i := 0
+  for v := p.l.Front(); v != nil; v = v.Next() {
+    values[i] = v.Value
+    i++
+  }
+  return values
+}
diff --git a/lib/go/thrift/tsimple_json_protocol.go b/lib/go/thrift/tsimple_json_protocol.go
new file mode 100644
index 0000000..569dd9c
--- /dev/null
+++ b/lib/go/thrift/tsimple_json_protocol.go
@@ -0,0 +1,1281 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "bufio"
+  "bytes"
+  "container/vector"
+  "encoding/base64"
+  "fmt"
+  "io"
+  "json"
+  "math"
+  "os"
+  "strconv"
+  "strings"
+)
+
+type _ParseContext int
+
+const (
+  _CONTEXT_IN_TOPLEVEL          _ParseContext = 1
+  _CONTEXT_IN_LIST_FIRST        _ParseContext = 2
+  _CONTEXT_IN_LIST              _ParseContext = 3
+  _CONTEXT_IN_OBJECT_FIRST      _ParseContext = 4
+  _CONTEXT_IN_OBJECT_NEXT_KEY   _ParseContext = 5
+  _CONTEXT_IN_OBJECT_NEXT_VALUE _ParseContext = 6
+)
+
+func (p _ParseContext) String() string {
+  switch p {
+  case _CONTEXT_IN_TOPLEVEL:
+    return "TOPLEVEL"
+  case _CONTEXT_IN_LIST_FIRST:
+    return "LIST-FIRST"
+  case _CONTEXT_IN_LIST:
+    return "LIST"
+  case _CONTEXT_IN_OBJECT_FIRST:
+    return "OBJECT-FIRST"
+  case _CONTEXT_IN_OBJECT_NEXT_KEY:
+    return "OBJECT-NEXT-KEY"
+  case _CONTEXT_IN_OBJECT_NEXT_VALUE:
+    return "OBJECT-NEXT-VALUE"
+  }
+  return "UNKNOWN-PARSE-CONTEXT"
+}
+
+/**
+ * JSON protocol implementation for thrift.
+ *
+ * This protocol produces/consumes a simple output format
+ * suitable for parsing by scripting languages.  It should not be
+ * confused with the full-featured TJSONProtocol.
+ *
+ */
+type TSimpleJSONProtocol struct {
+  //TProtocolBase;
+  trans TTransport
+
+  /**
+   * Stack of nested contexts that we may be in.
+   */
+  parseContextStack vector.IntVector
+  /**
+   * Stack of nested contexts that we may be in.
+   */
+  dumpContext vector.IntVector
+
+  /**
+   * Current context that we are in
+   */
+  writer TTransport
+  reader *bufio.Reader
+}
+
+/**
+ * Constructor
+ */
+func NewTSimpleJSONProtocol(t TTransport) *TSimpleJSONProtocol {
+  v := &TSimpleJSONProtocol{trans: t,
+    writer: t,
+    reader: bufio.NewReader(t),
+  }
+  v.parseContextStack.Push(int(_CONTEXT_IN_TOPLEVEL))
+  v.dumpContext.Push(int(_CONTEXT_IN_TOPLEVEL))
+  return v
+}
+
+/**
+ * Factory
+ */
+type TSimpleJSONProtocolFactory struct{}
+
+func (p *TSimpleJSONProtocolFactory) GetProtocol(trans TTransport) TProtocol {
+  return NewTSimpleJSONProtocol(trans)
+}
+
+func NewTSimpleJSONProtocolFactory() *TSimpleJSONProtocolFactory {
+  return &TSimpleJSONProtocolFactory{}
+}
+
+var (
+  JSON_COMMA                   []byte
+  JSON_COLON                   []byte
+  JSON_LBRACE                  []byte
+  JSON_RBRACE                  []byte
+  JSON_LBRACKET                []byte
+  JSON_RBRACKET                []byte
+  JSON_QUOTE                   byte
+  JSON_QUOTE_BYTES             []byte
+  JSON_NULL                    []byte
+  JSON_TRUE                    []byte
+  JSON_FALSE                   []byte
+  JSON_INFINITY                string
+  JSON_NEGATIVE_INFINITY       string
+  JSON_NAN                     string
+  JSON_INFINITY_BYTES          []byte
+  JSON_NEGATIVE_INFINITY_BYTES []byte
+  JSON_NAN_BYTES               []byte
+  json_nonbase_map_elem_bytes  []byte
+)
+
+func init() {
+  JSON_COMMA = []byte{','}
+  JSON_COLON = []byte{':'}
+  JSON_LBRACE = []byte{'{'}
+  JSON_RBRACE = []byte{'}'}
+  JSON_LBRACKET = []byte{'['}
+  JSON_RBRACKET = []byte{']'}
+  JSON_QUOTE = '"'
+  JSON_QUOTE_BYTES = []byte{'"'}
+  JSON_NULL = []byte{'n', 'u', 'l', 'l'}
+  JSON_TRUE = []byte{'t', 'r', 'u', 'e'}
+  JSON_FALSE = []byte{'f', 'a', 'l', 's', 'e'}
+  JSON_INFINITY = "Infinity"
+  JSON_NEGATIVE_INFINITY = "-Infinity"
+  JSON_NAN = "NaN"
+  JSON_INFINITY_BYTES = []byte{'I', 'n', 'f', 'i', 'n', 'i', 't', 'y'}
+  JSON_NEGATIVE_INFINITY_BYTES = []byte{'-', 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y'}
+  JSON_NAN_BYTES = []byte{'N', 'a', 'N'}
+  json_nonbase_map_elem_bytes = []byte{']', ',', '['}
+}
+
+func JsonQuote(s string) string {
+  b, _ := json.Marshal(s)
+  s1 := string(b)
+  return s1
+}
+
+func JsonUnquote(s string) (string, bool) {
+  s1 := new(string)
+  err := json.Unmarshal([]byte(s), s1)
+  return *s1, err == nil
+}
+
+
+func (p *TSimpleJSONProtocol) WriteMessageBegin(name string, typeId TMessageType, seqId int32) TProtocolException {
+  if e := p.OutputListBegin(); e != nil {
+    return e
+  }
+  if e := p.WriteString(name); e != nil {
+    return e
+  }
+  if e := p.WriteByte(byte(typeId)); e != nil {
+    return e
+  }
+  if e := p.WriteI32(seqId); e != nil {
+    return e
+  }
+  return nil
+}
+
+func (p *TSimpleJSONProtocol) WriteMessageEnd() TProtocolException {
+  return p.OutputListEnd()
+}
+
+func (p *TSimpleJSONProtocol) WriteStructBegin(name string) TProtocolException {
+  if e := p.OutputObjectBegin(); e != nil {
+    return e
+  }
+  return nil
+}
+
+func (p *TSimpleJSONProtocol) WriteStructEnd() TProtocolException {
+  return p.OutputObjectEnd()
+}
+
+func (p *TSimpleJSONProtocol) WriteFieldBegin(name string, typeId TType, id int16) TProtocolException {
+  if e := p.WriteString(name); e != nil {
+    return e
+  }
+  return nil
+  /*
+    	if e := p.OutputListBegin(); e != nil {
+        return e
+      }
+      if e := p.WriteByte(byte(typeId)); e != nil {
+        return e
+      }
+      return p.WriteI16(id)
+  */
+}
+
+func (p *TSimpleJSONProtocol) WriteFieldEnd() TProtocolException {
+  //return p.OutputListEnd()
+  return nil
+}
+
+func (p *TSimpleJSONProtocol) WriteFieldStop() TProtocolException { return nil }
+
+func (p *TSimpleJSONProtocol) WriteMapBegin(keyType TType, valueType TType, size int) TProtocolException {
+  if e := p.OutputListBegin(); e != nil {
+    return e
+  }
+  if e := p.WriteByte(byte(keyType)); e != nil {
+    return e
+  }
+  if e := p.WriteByte(byte(valueType)); e != nil {
+    return e
+  }
+  return p.WriteI32(int32(size))
+}
+
+func (p *TSimpleJSONProtocol) WriteMapEnd() TProtocolException {
+  return p.OutputListEnd()
+}
+
+func (p *TSimpleJSONProtocol) WriteListBegin(elemType TType, size int) TProtocolException {
+  return p.OutputElemListBegin(elemType, size)
+}
+
+func (p *TSimpleJSONProtocol) WriteListEnd() TProtocolException {
+  return p.OutputListEnd()
+}
+
+func (p *TSimpleJSONProtocol) WriteSetBegin(elemType TType, size int) TProtocolException {
+  return p.OutputElemListBegin(elemType, size)
+}
+
+func (p *TSimpleJSONProtocol) WriteSetEnd() TProtocolException {
+  return p.OutputListEnd()
+}
+
+func (p *TSimpleJSONProtocol) WriteBool(b bool) TProtocolException {
+  return p.OutputBool(b)
+}
+
+func (p *TSimpleJSONProtocol) WriteByte(b byte) TProtocolException {
+  return p.WriteI32(int32(b))
+}
+
+func (p *TSimpleJSONProtocol) WriteI16(v int16) TProtocolException {
+  return p.WriteI32(int32(v))
+}
+
+func (p *TSimpleJSONProtocol) WriteI32(v int32) TProtocolException {
+  return p.OutputI64(int64(v))
+}
+
+func (p *TSimpleJSONProtocol) WriteI64(v int64) TProtocolException {
+  return p.OutputI64(int64(v))
+}
+
+func (p *TSimpleJSONProtocol) WriteDouble(v float64) TProtocolException {
+  return p.OutputF64(v)
+}
+
+func (p *TSimpleJSONProtocol) WriteString(v string) TProtocolException {
+  return p.OutputString(v)
+}
+
+func (p *TSimpleJSONProtocol) WriteBinary(v []byte) TProtocolException {
+  // JSON library only takes in a string, 
+  // not an arbitrary byte array, to ensure bytes are transmitted
+  // efficiently we must convert this into a valid JSON string
+  // therefore we use base64 encoding to avoid excessive escaping/quoting
+  if e := p.OutputPreValue(); e != nil {
+    return e
+  }
+  if _, e := p.writer.Write(JSON_QUOTE_BYTES); e != nil {
+    return NewTProtocolExceptionFromOsError(e)
+  }
+  writer := base64.NewEncoder(base64.StdEncoding, p.writer)
+  if _, e := writer.Write(v); e != nil {
+    return NewTProtocolExceptionFromOsError(e)
+  }
+  if e := writer.Close(); e != nil {
+    return NewTProtocolExceptionFromOsError(e)
+  }
+  if _, e := p.writer.Write(JSON_QUOTE_BYTES); e != nil {
+    return NewTProtocolExceptionFromOsError(e)
+  }
+  return p.OutputPostValue()
+}
+
+/**
+ * Reading methods.
+ */
+
+func (p *TSimpleJSONProtocol) ReadMessageBegin() (name string, typeId TMessageType, seqId int32, err TProtocolException) {
+  if isNull, err := p.ParseListBegin(); isNull || err != nil {
+    return name, typeId, seqId, err
+  }
+  if name, err = p.ReadString(); err != nil {
+    return name, typeId, seqId, err
+  }
+  bTypeId, err := p.ReadByte()
+  typeId = TMessageType(bTypeId)
+  if err != nil {
+    return name, typeId, seqId, err
+  }
+  if seqId, err = p.ReadI32(); err != nil {
+    return name, typeId, seqId, err
+  }
+  return name, typeId, seqId, nil
+}
+
+func (p *TSimpleJSONProtocol) ReadMessageEnd() TProtocolException {
+  return p.ParseListEnd()
+}
+
+func (p *TSimpleJSONProtocol) ReadStructBegin() (name string, err TProtocolException) {
+  _, err = p.ParseObjectStart()
+  return "", err
+}
+
+func (p *TSimpleJSONProtocol) ReadStructEnd() TProtocolException {
+  return p.ParseObjectEnd()
+}
+
+func (p *TSimpleJSONProtocol) ReadFieldBegin() (string, TType, int16, TProtocolException) {
+  if err := p.ParsePreValue(); err != nil {
+    return "", STOP, 0, err
+  }
+  if p.reader.Buffered() < 1 {
+    return "", STOP, 0, nil
+  }
+  b, _ := p.reader.Peek(1)
+  if len(b) > 0 {
+    switch b[0] {
+    case JSON_RBRACE[0]:
+      return "", STOP, 0, nil
+    case JSON_QUOTE:
+      p.reader.ReadByte()
+      name, err := p.ParseStringBody()
+      if err != nil {
+        return name, STOP, 0, err
+      }
+      return name, GENERIC, -1, p.ParsePostValue()
+      /*
+         if err = p.ParsePostValue(); err != nil {
+           return name, STOP, 0, err
+         }
+         if isNull, err := p.ParseListBegin(); isNull || err != nil {
+           return name, STOP, 0, err
+         }
+         bType, err := p.ReadByte()
+         thetype := TType(bType)
+         if err != nil {
+           return name, thetype, 0, err
+         }
+         id, err := p.ReadI16()
+         return name, thetype, id, err
+      */
+    }
+    return "", STOP, 0, NewTProtocolException(INVALID_DATA, fmt.Sprint("Expected \"}\" or '\"', but found: '", string(b), "'"))
+  }
+  return "", STOP, 0, NewTProtocolExceptionFromOsError(os.EOF)
+}
+
+func (p *TSimpleJSONProtocol) ReadFieldEnd() TProtocolException {
+  return nil
+  //return p.ParseListEnd()
+}
+
+func (p *TSimpleJSONProtocol) ReadMapBegin() (keyType TType, valueType TType, size int, e TProtocolException) {
+  if isNull, e := p.ParseListBegin(); isNull || e != nil {
+    return VOID, VOID, 0, e
+  }
+
+  // read keyType
+  bKeyType, e := p.ReadByte()
+  keyType = TType(bKeyType)
+  if e != nil {
+    return keyType, valueType, size, e
+  }
+
+  // read valueType
+  bValueType, e := p.ReadByte()
+  valueType = TType(bValueType)
+  if e != nil {
+    return keyType, valueType, size, e
+  }
+
+  // read size
+  iSize, err := p.ReadI64()
+  size = int(iSize)
+  return keyType, valueType, size, err
+}
+
+func (p *TSimpleJSONProtocol) ReadMapEnd() TProtocolException {
+  return p.ParseListEnd()
+}
+
+func (p *TSimpleJSONProtocol) ReadListBegin() (elemType TType, size int, e TProtocolException) {
+  return p.ParseElemListBegin()
+}
+
+func (p *TSimpleJSONProtocol) ReadListEnd() TProtocolException {
+  return p.ParseListEnd()
+}
+
+func (p *TSimpleJSONProtocol) ReadSetBegin() (elemType TType, size int, e TProtocolException) {
+  return p.ParseElemListBegin()
+}
+
+func (p *TSimpleJSONProtocol) ReadSetEnd() TProtocolException {
+  return p.ParseListEnd()
+}
+
+func (p *TSimpleJSONProtocol) ReadBool() (bool, TProtocolException) {
+  var value bool
+  if err := p.ParsePreValue(); err != nil {
+    return value, err
+  }
+  b, _ := p.reader.Peek(len(JSON_FALSE))
+  if len(b) > 0 {
+    switch b[0] {
+    case JSON_TRUE[0]:
+      if string(b[0:len(JSON_TRUE)]) == string(JSON_TRUE) {
+        p.reader.Read(b[0:len(JSON_TRUE)])
+        value = true
+      } else {
+        return value, NewTProtocolException(INVALID_DATA, "Expected \"true\" but found: "+string(b))
+      }
+      break
+    case JSON_FALSE[0]:
+      if string(b[0:len(JSON_FALSE)]) == string(JSON_FALSE) {
+        p.reader.Read(b[0:len(JSON_FALSE)])
+        value = false
+      } else {
+        return value, NewTProtocolException(INVALID_DATA, "Expected \"false\" but found: "+string(b))
+      }
+      break
+    case JSON_NULL[0]:
+      if string(b[0:len(JSON_NULL)]) == string(JSON_NULL) {
+        p.reader.Read(b[0:len(JSON_NULL)])
+        value = false
+      } else {
+        return value, NewTProtocolException(INVALID_DATA, "Expected \"null\" but found: "+string(b))
+      }
+    default:
+      return value, NewTProtocolException(INVALID_DATA, "Expected \"true\", \"false\", or \"null\" but found: "+string(b))
+    }
+  }
+  return value, p.ParsePostValue()
+}
+
+func (p *TSimpleJSONProtocol) ReadByte() (byte, TProtocolException) {
+  v, err := p.ReadI64()
+  return byte(v), err
+}
+
+func (p *TSimpleJSONProtocol) ReadI16() (int16, TProtocolException) {
+  v, err := p.ReadI64()
+  return int16(v), err
+}
+
+func (p *TSimpleJSONProtocol) ReadI32() (int32, TProtocolException) {
+  v, err := p.ReadI64()
+  return int32(v), err
+}
+
+func (p *TSimpleJSONProtocol) ReadI64() (int64, TProtocolException) {
+  v, _, err := p.ParseI64()
+  return v, err
+}
+
+func (p *TSimpleJSONProtocol) ReadDouble() (float64, TProtocolException) {
+  v, _, err := p.ParseF64()
+  return v, err
+}
+
+func (p *TSimpleJSONProtocol) ReadString() (string, TProtocolException) {
+  var v string
+  if err := p.ParsePreValue(); err != nil {
+    return v, err
+  }
+  b, _ := p.reader.Peek(len(JSON_NULL))
+  if len(b) > 0 && b[0] == JSON_QUOTE {
+    p.reader.ReadByte()
+    value, err := p.ParseStringBody()
+    v = value
+    if err != nil {
+      return v, err
+    }
+  } else if len(b) >= len(JSON_NULL) && string(b[0:len(JSON_NULL)]) == string(JSON_NULL) {
+    _, err := p.reader.Read(b[0:len(JSON_NULL)])
+    if err != nil {
+      return v, NewTProtocolExceptionFromOsError(err)
+    }
+  } else {
+    return v, NewTProtocolException(INVALID_DATA, fmt.Sprint("Expected a JSON string, found ", string(b)))
+  }
+  return v, p.ParsePostValue()
+}
+
+func (p *TSimpleJSONProtocol) ReadBinary() ([]byte, TProtocolException) {
+  var v []byte
+  if err := p.ParsePreValue(); err != nil {
+    return nil, err
+  }
+  b, _ := p.reader.Peek(len(JSON_NULL))
+  if len(b) > 0 && b[0] == JSON_QUOTE {
+    p.reader.ReadByte()
+    value, err := p.ParseBase64EncodedBody()
+    v = value
+    if err != nil {
+      return v, err
+    }
+  } else if len(b) >= len(JSON_NULL) && string(b[0:len(JSON_NULL)]) == string(JSON_NULL) {
+    _, err := p.reader.Read(b[0:len(JSON_NULL)])
+    if err != nil {
+      return v, NewTProtocolExceptionFromOsError(err)
+    }
+  } else {
+    return v, NewTProtocolException(INVALID_DATA, fmt.Sprint("Expected a JSON string, found ", string(b)))
+  }
+  return v, p.ParsePostValue()
+}
+
+func (p *TSimpleJSONProtocol) Flush() (err TProtocolException) {
+  return NewTProtocolExceptionFromOsError(p.writer.Flush())
+}
+
+func (p *TSimpleJSONProtocol) Skip(fieldType TType) (err TProtocolException) {
+  return SkipDefaultDepth(p, fieldType)
+}
+
+func (p *TSimpleJSONProtocol) Transport() TTransport {
+  return p.trans
+}
+
+
+func (p *TSimpleJSONProtocol) OutputPreValue() TProtocolException {
+  cxt := _ParseContext(p.dumpContext.Last())
+  switch cxt {
+  case _CONTEXT_IN_LIST, _CONTEXT_IN_OBJECT_NEXT_KEY:
+    if _, e := p.writer.Write(JSON_COMMA); e != nil {
+      return NewTProtocolExceptionFromOsError(e)
+    }
+    break
+  case _CONTEXT_IN_OBJECT_NEXT_VALUE:
+    if _, e := p.writer.Write(JSON_COLON); e != nil {
+      return NewTProtocolExceptionFromOsError(e)
+    }
+    break
+  }
+  return nil
+}
+
+func (p *TSimpleJSONProtocol) OutputPostValue() TProtocolException {
+  cxt := _ParseContext(p.dumpContext.Last())
+  switch cxt {
+  case _CONTEXT_IN_LIST_FIRST:
+    p.dumpContext.Pop()
+    p.dumpContext.Push(int(_CONTEXT_IN_LIST))
+    break
+  case _CONTEXT_IN_OBJECT_FIRST:
+    p.dumpContext.Pop()
+    p.dumpContext.Push(int(_CONTEXT_IN_OBJECT_NEXT_VALUE))
+    break
+  case _CONTEXT_IN_OBJECT_NEXT_KEY:
+    p.dumpContext.Pop()
+    p.dumpContext.Push(int(_CONTEXT_IN_OBJECT_NEXT_VALUE))
+    break
+  case _CONTEXT_IN_OBJECT_NEXT_VALUE:
+    p.dumpContext.Pop()
+    p.dumpContext.Push(int(_CONTEXT_IN_OBJECT_NEXT_KEY))
+    break
+  }
+  return nil
+}
+
+func (p *TSimpleJSONProtocol) OutputBool(value bool) TProtocolException {
+  if e := p.OutputPreValue(); e != nil {
+    return e
+  }
+  var v string
+  if value {
+    v = string(JSON_TRUE)
+  } else {
+    v = string(JSON_FALSE)
+  }
+  switch _ParseContext(p.dumpContext.Last()) {
+  case _CONTEXT_IN_OBJECT_FIRST, _CONTEXT_IN_OBJECT_NEXT_KEY:
+    v = JsonQuote(v)
+  default:
+  }
+  if e := p.OutputStringData(v); e != nil {
+    return e
+  }
+  return p.OutputPostValue()
+}
+
+func (p *TSimpleJSONProtocol) OutputNull() TProtocolException {
+  if e := p.OutputPreValue(); e != nil {
+    return e
+  }
+  if _, e := p.writer.Write(JSON_NULL); e != nil {
+    return NewTProtocolExceptionFromOsError(e)
+  }
+  return p.OutputPostValue()
+}
+
+func (p *TSimpleJSONProtocol) OutputF64(value float64) TProtocolException {
+  if e := p.OutputPreValue(); e != nil {
+    return e
+  }
+  var v string
+  if math.IsNaN(value) {
+    v = string(JSON_QUOTE) + JSON_NAN + string(JSON_QUOTE)
+  } else if math.IsInf(value, 1) {
+    v = string(JSON_QUOTE) + JSON_INFINITY + string(JSON_QUOTE)
+  } else if math.IsInf(value, -1) {
+    v = string(JSON_QUOTE) + JSON_NEGATIVE_INFINITY + string(JSON_QUOTE)
+  } else {
+    v = strconv.Ftoa64(value, 'g', -1)
+    switch _ParseContext(p.dumpContext.Last()) {
+    case _CONTEXT_IN_OBJECT_FIRST, _CONTEXT_IN_OBJECT_NEXT_KEY:
+      v = string(JSON_QUOTE) + v + string(JSON_QUOTE)
+    default:
+    }
+  }
+  if e := p.OutputStringData(v); e != nil {
+    return e
+  }
+  return p.OutputPostValue()
+}
+
+func (p *TSimpleJSONProtocol) OutputI64(value int64) TProtocolException {
+  if e := p.OutputPreValue(); e != nil {
+    return e
+  }
+  v := strconv.Itoa64(value)
+  switch _ParseContext(p.dumpContext.Last()) {
+  case _CONTEXT_IN_OBJECT_FIRST, _CONTEXT_IN_OBJECT_NEXT_KEY:
+    v = JsonQuote(v)
+  default:
+  }
+  if e := p.OutputStringData(v); e != nil {
+    return e
+  }
+  return p.OutputPostValue()
+}
+
+func (p *TSimpleJSONProtocol) OutputString(s string) TProtocolException {
+  if e := p.OutputPreValue(); e != nil {
+    return e
+  }
+  if e := p.OutputStringData(JsonQuote(s)); e != nil {
+    return e
+  }
+  return p.OutputPostValue()
+}
+
+func (p *TSimpleJSONProtocol) OutputStringData(s string) TProtocolException {
+  _, e := io.Copyn(p.writer, strings.NewReader(s), int64(len(s)))
+  return NewTProtocolExceptionFromOsError(e)
+}
+
+func (p *TSimpleJSONProtocol) OutputObjectBegin() TProtocolException {
+  if e := p.OutputPreValue(); e != nil {
+    return e
+  }
+  if _, e := p.writer.Write(JSON_LBRACE); e != nil {
+    return NewTProtocolExceptionFromOsError(e)
+  }
+  p.dumpContext.Push(int(_CONTEXT_IN_OBJECT_FIRST))
+  return nil
+}
+
+func (p *TSimpleJSONProtocol) OutputObjectEnd() TProtocolException {
+  if _, e := p.writer.Write(JSON_RBRACE); e != nil {
+    return NewTProtocolExceptionFromOsError(e)
+  }
+  p.dumpContext.Pop()
+  if e := p.OutputPostValue(); e != nil {
+    return e
+  }
+  return nil
+}
+
+func (p *TSimpleJSONProtocol) OutputListBegin() TProtocolException {
+  if e := p.OutputPreValue(); e != nil {
+    return e
+  }
+  if _, e := p.writer.Write(JSON_LBRACKET); e != nil {
+    return NewTProtocolExceptionFromOsError(e)
+  }
+  p.dumpContext.Push(int(_CONTEXT_IN_LIST_FIRST))
+  return nil
+}
+
+func (p *TSimpleJSONProtocol) OutputListEnd() TProtocolException {
+  if _, e := p.writer.Write(JSON_RBRACKET); e != nil {
+    return NewTProtocolExceptionFromOsError(e)
+  }
+  p.dumpContext.Pop()
+  if e := p.OutputPostValue(); e != nil {
+    return e
+  }
+  return nil
+}
+
+func (p *TSimpleJSONProtocol) OutputElemListBegin(elemType TType, size int) TProtocolException {
+  if e := p.OutputListBegin(); e != nil {
+    return e
+  }
+  if e := p.WriteByte(byte(elemType)); e != nil {
+    return e
+  }
+  if e := p.WriteI64(int64(size)); e != nil {
+    return e
+  }
+  return nil
+}
+
+func (p *TSimpleJSONProtocol) ParsePreValue() TProtocolException {
+  if e := p.readNonSignificantWhitespace(); e != nil {
+    return NewTProtocolExceptionFromOsError(e)
+  }
+  cxt := _ParseContext(p.parseContextStack.Last())
+  if p.reader.Buffered() < 1 {
+    return nil
+  }
+  b, _ := p.reader.Peek(1)
+  switch cxt {
+  case _CONTEXT_IN_LIST:
+    if len(b) > 0 {
+      switch b[0] {
+      case JSON_RBRACKET[0]:
+        return nil
+      case JSON_COMMA[0]:
+        p.reader.ReadByte()
+        if e := p.readNonSignificantWhitespace(); e != nil {
+          return NewTProtocolExceptionFromOsError(e)
+        }
+        return nil
+      default:
+        return NewTProtocolException(INVALID_DATA, fmt.Sprint("Expected \"]\" or \",\" in list context, but found \"", string(b), "\""))
+      }
+    }
+    break
+  case _CONTEXT_IN_OBJECT_NEXT_KEY:
+    if len(b) > 0 {
+      switch b[0] {
+      case JSON_RBRACE[0]:
+        return nil
+      case JSON_COMMA[0]:
+        p.reader.ReadByte()
+        if e := p.readNonSignificantWhitespace(); e != nil {
+          return NewTProtocolExceptionFromOsError(e)
+        }
+        return nil
+      default:
+        return NewTProtocolException(INVALID_DATA, fmt.Sprint("Expected \"}\" or \",\" in object context, but found \"", string(b), "\""))
+      }
+    }
+    break
+  case _CONTEXT_IN_OBJECT_NEXT_VALUE:
+    if len(b) > 0 {
+      switch b[0] {
+      case JSON_COLON[0]:
+        p.reader.ReadByte()
+        if e := p.readNonSignificantWhitespace(); e != nil {
+          return NewTProtocolExceptionFromOsError(e)
+        }
+        return nil
+      default:
+        return NewTProtocolException(INVALID_DATA, fmt.Sprint("Expected \":\" in object context, but found \"", string(b), "\""))
+      }
+    }
+    break
+  }
+  return nil
+}
+
+func (p *TSimpleJSONProtocol) ParsePostValue() TProtocolException {
+  if e := p.readNonSignificantWhitespace(); e != nil {
+    return NewTProtocolExceptionFromOsError(e)
+  }
+  cxt := _ParseContext(p.parseContextStack.Last())
+  switch cxt {
+  case _CONTEXT_IN_LIST_FIRST:
+    p.parseContextStack.Pop()
+    p.parseContextStack.Push(int(_CONTEXT_IN_LIST))
+    break
+  case _CONTEXT_IN_OBJECT_FIRST, _CONTEXT_IN_OBJECT_NEXT_KEY:
+    p.parseContextStack.Pop()
+    p.parseContextStack.Push(int(_CONTEXT_IN_OBJECT_NEXT_VALUE))
+    break
+  case _CONTEXT_IN_OBJECT_NEXT_VALUE:
+    p.parseContextStack.Pop()
+    p.parseContextStack.Push(int(_CONTEXT_IN_OBJECT_NEXT_KEY))
+    break
+  }
+  return nil
+}
+
+func (p *TSimpleJSONProtocol) readNonSignificantWhitespace() os.Error {
+  for p.reader.Buffered() > 0 {
+    b, _ := p.reader.Peek(1)
+    if len(b) < 1 {
+      return nil
+    }
+    switch b[0] {
+    case ' ', '\r', '\n', '\t':
+      p.reader.ReadByte()
+      continue
+    default:
+      break
+    }
+    break
+  }
+  return nil
+}
+
+func (p *TSimpleJSONProtocol) ParseStringBody() (string, TProtocolException) {
+  line, err := p.reader.ReadString(JSON_QUOTE)
+  if err != nil {
+    return "", NewTProtocolExceptionFromOsError(err)
+  }
+  l := len(line)
+  // count number of escapes to see if we need to keep going
+  i := 1
+  for ; i < l; i++ {
+    if line[l-i-1] != '\\' {
+      break
+    }
+  }
+  if i&0x01 == 1 {
+    v, ok := JsonUnquote(string(JSON_QUOTE) + line)
+    if !ok {
+      return "", NewTProtocolExceptionFromOsError(err)
+    }
+    return v, nil
+  }
+  s, err := p.ParseQuotedStringBody()
+  if err != nil {
+    return "", NewTProtocolExceptionFromOsError(err)
+  }
+  str := string(JSON_QUOTE) + line + s
+  v, ok := JsonUnquote(str)
+  if !ok {
+    return "", NewTProtocolException(INVALID_DATA, "Unable to parse as JSON string "+str)
+  }
+  return v, nil
+}
+
+func (p *TSimpleJSONProtocol) ParseQuotedStringBody() (string, TProtocolException) {
+  line, err := p.reader.ReadString(JSON_QUOTE)
+  if err != nil {
+    return "", NewTProtocolExceptionFromOsError(err)
+  }
+  l := len(line)
+  // count number of escapes to see if we need to keep going
+  i := 1
+  for ; i < l; i++ {
+    if line[l-i-1] != '\\' {
+      break
+    }
+  }
+  if i&0x01 == 1 {
+    return line, nil
+  }
+  s, err := p.ParseQuotedStringBody()
+  if err != nil {
+    return "", NewTProtocolExceptionFromOsError(err)
+  }
+  v := line + s
+  return v, nil
+}
+
+func (p *TSimpleJSONProtocol) ParseBase64EncodedBody() ([]byte, TProtocolException) {
+  line, err := p.reader.ReadBytes(JSON_QUOTE)
+  if err != nil {
+    return line, NewTProtocolExceptionFromOsError(err)
+  }
+  line2 := line[0 : len(line)-1]
+  l := len(line2)
+  output := make([]byte, base64.StdEncoding.DecodedLen(l))
+  n, err := base64.StdEncoding.Decode(output, line2)
+  return output[0:n], NewTProtocolExceptionFromOsError(err)
+}
+
+func (p *TSimpleJSONProtocol) ParseI64() (int64, bool, TProtocolException) {
+  if err := p.ParsePreValue(); err != nil {
+    return 0, false, err
+  }
+  var value int64
+  var isnull bool
+  b, _ := p.reader.Peek(len(JSON_NULL))
+  if len(b) >= len(JSON_NULL) && string(b) == string(JSON_NULL) {
+    p.reader.Read(b[0:len(JSON_NULL)])
+    isnull = true
+  } else {
+    num, err := p.readNumeric()
+    isnull = (num == nil)
+    if !isnull {
+      value = num.Int64()
+    }
+    if err != nil {
+      return value, isnull, err
+    }
+  }
+  return value, isnull, p.ParsePostValue()
+}
+
+func (p *TSimpleJSONProtocol) ParseF64() (float64, bool, TProtocolException) {
+  if err := p.ParsePreValue(); err != nil {
+    return 0, false, err
+  }
+  var value float64
+  var isnull bool
+  b, _ := p.reader.Peek(len(JSON_NULL))
+  if len(b) >= len(JSON_NULL) && string(b) == string(JSON_NULL) {
+    p.reader.Read(b[0:len(JSON_NULL)])
+    isnull = true
+  } else {
+    num, err := p.readNumeric()
+    isnull = (num == nil)
+    if !isnull {
+      value = num.Float64()
+    }
+    if err != nil {
+      return value, isnull, err
+    }
+  }
+  return value, isnull, p.ParsePostValue()
+}
+
+func (p *TSimpleJSONProtocol) ParseObjectStart() (bool, TProtocolException) {
+  if err := p.ParsePreValue(); err != nil {
+    return false, err
+  }
+  b, _ := p.reader.Peek(len(JSON_NULL))
+  if len(b) > 0 && b[0] == JSON_LBRACE[0] {
+    p.reader.ReadByte()
+    p.parseContextStack.Push(int(_CONTEXT_IN_OBJECT_FIRST))
+    return false, nil
+  } else if len(b) >= len(JSON_NULL) && string(b[0:len(JSON_NULL)]) == string(JSON_NULL) {
+    return true, nil
+  }
+  return false, NewTProtocolException(INVALID_DATA, fmt.Sprint("Expected '{' or null, but found '", string(b), "'"))
+}
+
+func (p *TSimpleJSONProtocol) ParseObjectEnd() TProtocolException {
+  if isNull, err := p.readIfNull(); isNull || err != nil {
+    return err
+  }
+  cxt := _ParseContext(p.parseContextStack.Last())
+  if cxt != _CONTEXT_IN_OBJECT_FIRST && cxt != _CONTEXT_IN_OBJECT_NEXT_KEY {
+    return NewTProtocolException(INVALID_DATA, fmt.Sprint("Expected to be in the Object Context, but not in Object Context"))
+  }
+  line, err := p.reader.ReadString(JSON_RBRACE[0])
+  if err != nil {
+    return NewTProtocolExceptionFromOsError(err)
+  }
+  for _, char := range line {
+    switch char {
+    default:
+      return NewTProtocolException(INVALID_DATA, fmt.Sprint("Expecting end of object \"}\", but found: \"", line, "\""))
+    case ' ', '\n', '\r', '\t', '}':
+      break
+    }
+  }
+  p.parseContextStack.Pop()
+  return p.ParsePostValue()
+}
+
+func (p *TSimpleJSONProtocol) ParseListBegin() (bool, TProtocolException) {
+  if e := p.ParsePreValue(); e != nil {
+    return false, e
+  }
+  b, e := p.reader.Peek(len(JSON_NULL))
+  if e == nil && len(b) >= 1 && b[0] == JSON_LBRACKET[0] {
+    p.parseContextStack.Push(int(_CONTEXT_IN_LIST_FIRST))
+    p.reader.ReadByte()
+    return false, nil
+  } else if e == nil && len(b) >= len(JSON_NULL) && string(b) == string(JSON_NULL) {
+    return true, nil
+  }
+  return false, NewTProtocolException(INVALID_DATA, fmt.Sprintf("Expected 'null' or '{', received '%q'", b))
+}
+
+func (p *TSimpleJSONProtocol) ParseElemListBegin() (elemType TType, size int, e TProtocolException) {
+  if isNull, e := p.ParseListBegin(); isNull || e != nil {
+    return VOID, 0, e
+  }
+  bElemType, err := p.ReadByte()
+  elemType = TType(bElemType)
+  if err != nil {
+    return elemType, size, err
+  }
+  nSize, err2 := p.ReadI64()
+  size = int(nSize)
+  return elemType, size, err2
+}
+
+func (p *TSimpleJSONProtocol) ParseListEnd() TProtocolException {
+  if isNull, err := p.readIfNull(); isNull || err != nil {
+    return err
+  }
+  if _ParseContext(p.parseContextStack.Last()) != _CONTEXT_IN_LIST {
+    return NewTProtocolException(INVALID_DATA, "Expected to be in the List Context, but not in List Context")
+  }
+  line, err := p.reader.ReadString(JSON_RBRACKET[0])
+  if err != nil {
+    return NewTProtocolExceptionFromOsError(err)
+  }
+  for _, char := range line {
+    switch char {
+    default:
+      return NewTProtocolException(INVALID_DATA, fmt.Sprint("Expecting end of list \"]\", but found: \"", line, "\""))
+    case ' ', '\n', '\r', '\t', int(JSON_RBRACKET[0]):
+      break
+    }
+  }
+  p.parseContextStack.Pop()
+  return p.ParsePostValue()
+}
+
+func (p *TSimpleJSONProtocol) readSingleValue() (interface{}, TType, TProtocolException) {
+  e := p.readNonSignificantWhitespace()
+  if e != nil {
+    return nil, VOID, NewTProtocolExceptionFromOsError(e)
+  }
+  b, e := p.reader.Peek(10)
+  if len(b) > 0 {
+    c := b[0]
+    switch c {
+    case JSON_NULL[0]:
+      buf := make([]byte, len(JSON_NULL))
+      _, e := p.reader.Read(buf)
+      if e != nil {
+        return nil, VOID, NewTProtocolExceptionFromOsError(e)
+      }
+      if string(JSON_NULL) != string(buf) {
+        e := NewTProtocolException(INVALID_DATA, "Expected '"+string(JSON_NULL)+"' but found '"+string(buf)+"' while parsing JSON.")
+        return nil, VOID, e
+      }
+      return nil, VOID, nil
+    case JSON_QUOTE:
+      p.reader.ReadByte()
+      v, e := p.ParseStringBody()
+      if e != nil {
+        return v, UTF8, NewTProtocolExceptionFromOsError(e)
+      }
+      if v == JSON_INFINITY {
+        return INFINITY, DOUBLE, nil
+      } else if v == JSON_NEGATIVE_INFINITY {
+        return NEGATIVE_INFINITY, DOUBLE, nil
+      } else if v == JSON_NAN {
+        return NAN, DOUBLE, nil
+      }
+      return v, UTF8, nil
+    case JSON_TRUE[0]:
+      buf := make([]byte, len(JSON_TRUE))
+      _, e := p.reader.Read(buf)
+      if e != nil {
+        return true, BOOL, NewTProtocolExceptionFromOsError(e)
+      }
+      if string(JSON_TRUE) != string(buf) {
+        e := NewTProtocolException(INVALID_DATA, "Expected '"+string(JSON_TRUE)+"' but found '"+string(buf)+"' while parsing JSON.")
+        return true, BOOL, NewTProtocolExceptionFromOsError(e)
+      }
+      return true, BOOL, nil
+    case JSON_FALSE[0]:
+      buf := make([]byte, len(JSON_FALSE))
+      _, e := p.reader.Read(buf)
+      if e != nil {
+        return false, BOOL, NewTProtocolExceptionFromOsError(e)
+      }
+      if string(JSON_FALSE) != string(buf) {
+        e := NewTProtocolException(INVALID_DATA, "Expected '"+string(JSON_FALSE)+"' but found '"+string(buf)+"' while parsing JSON.")
+        return false, BOOL, NewTProtocolExceptionFromOsError(e)
+      }
+      return false, BOOL, nil
+    case JSON_LBRACKET[0]:
+      _, e := p.reader.ReadByte()
+      return make([]interface{}, 0), LIST, NewTProtocolExceptionFromOsError(e)
+    case JSON_LBRACE[0]:
+      _, e := p.reader.ReadByte()
+      return make(map[string]interface{}), STRUCT, NewTProtocolExceptionFromOsError(e)
+    case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'e', 'E', '.', '+', '-', JSON_INFINITY[0], JSON_NAN[0]:
+      // assume numeric
+      v, e := p.readNumeric()
+      return v, DOUBLE, e
+    default:
+      return nil, VOID, NewTProtocolException(INVALID_DATA, "Expected element in list but found '"+string(c)+"' while parsing JSON.")
+    }
+  }
+  return nil, VOID, NewTProtocolException(INVALID_DATA, "Cannot read a single element while parsing JSON.")
+
+}
+
+
+func (p *TSimpleJSONProtocol) readIfNull() (bool, TProtocolException) {
+  cont := true
+  for p.reader.Buffered() > 0 && cont {
+    b, _ := p.reader.Peek(1)
+    if len(b) < 1 {
+      return false, nil
+    }
+    switch b[0] {
+    default:
+      return false, nil
+    case JSON_NULL[0]:
+      cont = false
+      break
+    case ' ', '\n', '\r', '\t':
+      p.reader.ReadByte()
+      break
+    }
+  }
+  if p.reader.Buffered() == 0 {
+    return false, nil
+  }
+  b, _ := p.reader.Peek(len(JSON_NULL))
+  if string(b) == string(JSON_NULL) {
+    p.reader.Read(b[0:len(JSON_NULL)])
+    return true, nil
+  }
+  return false, nil
+}
+
+func (p *TSimpleJSONProtocol) readQuoteIfNext() {
+  if p.reader.Buffered() < 1 {
+    return
+  }
+  b, _ := p.reader.Peek(1)
+  if len(b) > 0 && b[0] == JSON_QUOTE {
+    p.reader.ReadByte()
+  }
+}
+
+func (p *TSimpleJSONProtocol) readNumeric() (Numeric, TProtocolException) {
+  isNull, err := p.readIfNull()
+  if isNull || err != nil {
+    return NUMERIC_NULL, err
+  }
+  hasDecimalPoint := false
+  nextCanBeSign := true
+  hasE := false
+  MAX_LEN := 40
+  buf := bytes.NewBuffer(make([]byte, 0, MAX_LEN))
+  continueFor := true
+  inQuotes := false
+  for continueFor {
+    c, err := p.reader.ReadByte()
+    if err != nil {
+      if err == os.EOF {
+        break
+      }
+      return NUMERIC_NULL, NewTProtocolExceptionFromOsError(err)
+    }
+    switch c {
+    case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+      buf.WriteByte(c)
+      nextCanBeSign = false
+    case '.':
+      if hasDecimalPoint {
+        return NUMERIC_NULL, NewTProtocolException(INVALID_DATA, fmt.Sprintf("Unable to parse number with multiple decimal points '%s.'", buf.String()))
+      }
+      if hasE {
+        return NUMERIC_NULL, NewTProtocolException(INVALID_DATA, fmt.Sprintf("Unable to parse number with decimal points in the exponent '%s.'", buf.String()))
+      }
+      buf.WriteByte(c)
+      hasDecimalPoint, nextCanBeSign = true, false
+    case 'e', 'E':
+      if hasE {
+        return NUMERIC_NULL, NewTProtocolException(INVALID_DATA, fmt.Sprintf("Unable to parse number with multiple exponents '%s%c'", buf.String(), c))
+      }
+      buf.WriteByte(c)
+      hasE, nextCanBeSign = true, true
+    case '-', '+':
+      if !nextCanBeSign {
+        return NUMERIC_NULL, NewTProtocolException(INVALID_DATA, fmt.Sprint("Negative sign within number"))
+      }
+      buf.WriteByte(c)
+      nextCanBeSign = false
+    case ' ', 0, '\t', '\n', '\r', JSON_RBRACE[0], JSON_RBRACKET[0], JSON_COMMA[0], JSON_COLON[0]:
+      p.reader.UnreadByte()
+      continueFor = false
+    case JSON_NAN[0]:
+      if buf.Len() == 0 {
+        buffer := make([]byte, len(JSON_NAN))
+        buffer[0] = c
+        _, e := p.reader.Read(buffer[1:])
+        if e != nil {
+          return NUMERIC_NULL, NewTProtocolExceptionFromOsError(e)
+        }
+        if JSON_NAN != string(buffer) {
+          e := NewTProtocolException(INVALID_DATA, "Expected '"+JSON_NAN+"' but found '"+string(buffer)+"' while parsing JSON.")
+          return NUMERIC_NULL, e
+        }
+        if inQuotes {
+          p.readQuoteIfNext()
+        }
+        return NAN, nil
+      } else {
+        return NUMERIC_NULL, NewTProtocolException(INVALID_DATA, fmt.Sprintf("Unable to parse number starting with character '%c'", c))
+      }
+    case JSON_INFINITY[0]:
+      if buf.Len() == 0 || (buf.Len() == 1 && buf.Bytes()[0] == '+') {
+        buffer := make([]byte, len(JSON_INFINITY))
+        buffer[0] = c
+        _, e := p.reader.Read(buffer[1:])
+        if e != nil {
+          return NUMERIC_NULL, NewTProtocolExceptionFromOsError(e)
+        }
+        if JSON_INFINITY != string(buffer) {
+          e := NewTProtocolException(INVALID_DATA, "Expected '"+JSON_INFINITY+"' but found '"+string(buffer)+"' while parsing JSON.")
+          return NUMERIC_NULL, e
+        }
+        if inQuotes {
+          p.readQuoteIfNext()
+        }
+        return INFINITY, nil
+      } else if buf.Len() == 1 && buf.Bytes()[0] == JSON_NEGATIVE_INFINITY[0] {
+        buffer := make([]byte, len(JSON_NEGATIVE_INFINITY))
+        buffer[0] = JSON_NEGATIVE_INFINITY[0]
+        buffer[1] = c
+        _, e := p.reader.Read(buffer[2:])
+        if e != nil {
+          return NUMERIC_NULL, NewTProtocolExceptionFromOsError(e)
+        }
+        if JSON_NEGATIVE_INFINITY != string(buffer) {
+          e := NewTProtocolException(INVALID_DATA, "Expected '"+JSON_NEGATIVE_INFINITY+"' but found '"+string(buffer)+"' while parsing JSON.")
+          return NUMERIC_NULL, e
+        }
+        if inQuotes {
+          p.readQuoteIfNext()
+        }
+        return NEGATIVE_INFINITY, nil
+      } else {
+        return NUMERIC_NULL, NewTProtocolException(INVALID_DATA, fmt.Sprintf("Unable to parse number starting with character '%c' due to existing buffer %s", c, buf.String()))
+      }
+    case JSON_QUOTE:
+      if !inQuotes {
+        inQuotes = true
+      } else {
+        break
+      }
+    default:
+      return NUMERIC_NULL, NewTProtocolException(INVALID_DATA, fmt.Sprintf("Unable to parse number starting with character '%c'", c))
+    }
+  }
+  if buf.Len() == 0 {
+    return NUMERIC_NULL, NewTProtocolException(INVALID_DATA, fmt.Sprint("Unable to parse number from empty string ''"))
+  }
+  return NewNumericFromJSONString(buf.String(), false), nil
+}
diff --git a/lib/go/thrift/tsimple_json_protocol_test.go b/lib/go/thrift/tsimple_json_protocol_test.go
new file mode 100644
index 0000000..e57d55b
--- /dev/null
+++ b/lib/go/thrift/tsimple_json_protocol_test.go
@@ -0,0 +1,662 @@
+/*
+ * 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.
+ */
+
+package thrift_test
+
+import (
+  . "thrift"
+  "encoding/base64"
+  "fmt"
+  "json"
+  "math"
+  "strconv"
+  "strings"
+  "testing"
+)
+
+func TestWriteSimpleJSONProtocolBool(t *testing.T) {
+  thetype := "boolean"
+  trans := NewTMemoryBuffer()
+  p := NewTSimpleJSONProtocol(trans)
+  for _, value := range BOOL_VALUES {
+    if e := p.WriteBool(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if e := p.Flush(); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+    }
+    s := trans.String()
+    if s != fmt.Sprint(value) {
+      t.Fatalf("Bad value for %s %v: %s", thetype, value, s)
+    }
+    v := false
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestReadSimpleJSONProtocolBool(t *testing.T) {
+  thetype := "boolean"
+  for _, value := range BOOL_VALUES {
+    trans := NewTMemoryBuffer()
+    p := NewTSimpleJSONProtocol(trans)
+    if value {
+      trans.Write(JSON_TRUE)
+    } else {
+      trans.Write(JSON_FALSE)
+    }
+    trans.Flush()
+    s := trans.String()
+    v, e := p.ReadBool()
+    if e != nil {
+      t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if v != value {
+      t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+    }
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+    trans.Close()
+  }
+}
+
+func TestWriteSimpleJSONProtocolByte(t *testing.T) {
+  thetype := "byte"
+  trans := NewTMemoryBuffer()
+  p := NewTSimpleJSONProtocol(trans)
+  for _, value := range BYTE_VALUES {
+    if e := p.WriteByte(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if e := p.Flush(); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+    }
+    s := trans.String()
+    if s != fmt.Sprint(value) {
+      t.Fatalf("Bad value for %s %v: %s", thetype, value, s)
+    }
+    v := byte(0)
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestReadSimpleJSONProtocolByte(t *testing.T) {
+  thetype := "byte"
+  for _, value := range BYTE_VALUES {
+    trans := NewTMemoryBuffer()
+    p := NewTSimpleJSONProtocol(trans)
+    trans.WriteString(strconv.Itoa(int(value)))
+    trans.Flush()
+    s := trans.String()
+    v, e := p.ReadByte()
+    if e != nil {
+      t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if v != value {
+      t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+    }
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+    trans.Close()
+  }
+}
+
+func TestWriteSimpleJSONProtocolI16(t *testing.T) {
+  thetype := "int16"
+  trans := NewTMemoryBuffer()
+  p := NewTSimpleJSONProtocol(trans)
+  for _, value := range INT16_VALUES {
+    if e := p.WriteI16(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if e := p.Flush(); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+    }
+    s := trans.String()
+    if s != fmt.Sprint(value) {
+      t.Fatalf("Bad value for %s %v: %s", thetype, value, s)
+    }
+    v := int16(0)
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestReadSimpleJSONProtocolI16(t *testing.T) {
+  thetype := "int16"
+  for _, value := range INT16_VALUES {
+    trans := NewTMemoryBuffer()
+    p := NewTSimpleJSONProtocol(trans)
+    trans.WriteString(strconv.Itoa(int(value)))
+    trans.Flush()
+    s := trans.String()
+    v, e := p.ReadI16()
+    if e != nil {
+      t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if v != value {
+      t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+    }
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+    trans.Close()
+  }
+}
+
+func TestWriteSimpleJSONProtocolI32(t *testing.T) {
+  thetype := "int32"
+  trans := NewTMemoryBuffer()
+  p := NewTSimpleJSONProtocol(trans)
+  for _, value := range INT32_VALUES {
+    if e := p.WriteI32(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if e := p.Flush(); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+    }
+    s := trans.String()
+    if s != fmt.Sprint(value) {
+      t.Fatalf("Bad value for %s %v: %s", thetype, value, s)
+    }
+    v := int32(0)
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestReadSimpleJSONProtocolI32(t *testing.T) {
+  thetype := "int32"
+  for _, value := range INT32_VALUES {
+    trans := NewTMemoryBuffer()
+    p := NewTSimpleJSONProtocol(trans)
+    trans.WriteString(strconv.Itoa(int(value)))
+    trans.Flush()
+    s := trans.String()
+    v, e := p.ReadI32()
+    if e != nil {
+      t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if v != value {
+      t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+    }
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+    trans.Close()
+  }
+}
+
+func TestWriteSimpleJSONProtocolI64(t *testing.T) {
+  thetype := "int64"
+  trans := NewTMemoryBuffer()
+  p := NewTSimpleJSONProtocol(trans)
+  for _, value := range INT64_VALUES {
+    if e := p.WriteI64(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if e := p.Flush(); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+    }
+    s := trans.String()
+    if s != fmt.Sprint(value) {
+      t.Fatalf("Bad value for %s %v: %s", thetype, value, s)
+    }
+    v := int64(0)
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestReadSimpleJSONProtocolI64(t *testing.T) {
+  thetype := "int64"
+  for _, value := range INT64_VALUES {
+    trans := NewTMemoryBuffer()
+    p := NewTSimpleJSONProtocol(trans)
+    trans.WriteString(strconv.Itoa64(value))
+    trans.Flush()
+    s := trans.String()
+    v, e := p.ReadI64()
+    if e != nil {
+      t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if v != value {
+      t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+    }
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+    trans.Close()
+  }
+}
+
+func TestWriteSimpleJSONProtocolDouble(t *testing.T) {
+  thetype := "double"
+  trans := NewTMemoryBuffer()
+  p := NewTSimpleJSONProtocol(trans)
+  for _, value := range DOUBLE_VALUES {
+    if e := p.WriteDouble(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if e := p.Flush(); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+    }
+    s := trans.String()
+    if math.IsInf(value, 1) {
+      if s != JsonQuote(JSON_INFINITY) {
+        t.Fatalf("Bad value for %s %v, wrote: %v, expected: %v", thetype, value, s, JsonQuote(JSON_INFINITY))
+      }
+    } else if math.IsInf(value, -1) {
+      if s != JsonQuote(JSON_NEGATIVE_INFINITY) {
+        t.Fatalf("Bad value for %s %v, wrote: %v, expected: %v", thetype, value, s, JsonQuote(JSON_NEGATIVE_INFINITY))
+      }
+    } else if math.IsNaN(value) {
+      if s != JsonQuote(JSON_NAN) {
+        t.Fatalf("Bad value for %s %v, wrote: %v, expected: %v", thetype, value, s, JsonQuote(JSON_NAN))
+      }
+    } else {
+      if s != fmt.Sprint(value) {
+        t.Fatalf("Bad value for %s %v: %s", thetype, value, s)
+      }
+      v := float64(0)
+      if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+        t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+      }
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestReadSimpleJSONProtocolDouble(t *testing.T) {
+  thetype := "double"
+  for _, value := range DOUBLE_VALUES {
+    trans := NewTMemoryBuffer()
+    p := NewTSimpleJSONProtocol(trans)
+    n := NewNumericFromDouble(value)
+    trans.WriteString(n.String())
+    trans.Flush()
+    s := trans.String()
+    v, e := p.ReadDouble()
+    if e != nil {
+      t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if math.IsInf(value, 1) {
+      if !math.IsInf(v, 1) {
+        t.Fatalf("Bad value for %s %v, wrote: %v, received: %v", thetype, value, s, v)
+      }
+    } else if math.IsInf(value, -1) {
+      if !math.IsInf(v, -1) {
+        t.Fatalf("Bad value for %s %v, wrote: %v, received: %v", thetype, value, s, v)
+      }
+    } else if math.IsNaN(value) {
+      if !math.IsNaN(v) {
+        t.Fatalf("Bad value for %s %v, wrote: %v, received: %v", thetype, value, s, v)
+      }
+    } else {
+      if v != value {
+        t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+      }
+      if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+        t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+      }
+    }
+    trans.Reset()
+    trans.Close()
+  }
+}
+
+func TestWriteSimpleJSONProtocolString(t *testing.T) {
+  thetype := "string"
+  trans := NewTMemoryBuffer()
+  p := NewTSimpleJSONProtocol(trans)
+  for _, value := range STRING_VALUES {
+    if e := p.WriteString(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if e := p.Flush(); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+    }
+    s := trans.String()
+    if s[0] != '"' || s[len(s)-1] != '"' {
+      t.Fatalf("Bad value for %s '%v', wrote '%v', expected: %v", thetype, value, s, fmt.Sprint("\"", value, "\""))
+    }
+    v := new(string)
+    if err := json.Unmarshal([]byte(s), v); err != nil || *v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, *v)
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestReadSimpleJSONProtocolString(t *testing.T) {
+  thetype := "string"
+  for _, value := range STRING_VALUES {
+    trans := NewTMemoryBuffer()
+    p := NewTSimpleJSONProtocol(trans)
+    trans.WriteString(JsonQuote(value))
+    trans.Flush()
+    s := trans.String()
+    v, e := p.ReadString()
+    if e != nil {
+      t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if v != value {
+      t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+    }
+    v1 := new(string)
+    if err := json.Unmarshal([]byte(s), v1); err != nil || *v1 != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, *v1)
+    }
+    trans.Reset()
+    trans.Close()
+  }
+}
+
+func TestWriteSimpleJSONProtocolBinary(t *testing.T) {
+  thetype := "binary"
+  value := protocol_bdata
+  b64value := make([]byte, base64.StdEncoding.EncodedLen(len(protocol_bdata)))
+  base64.StdEncoding.Encode(b64value, value)
+  b64String := string(b64value)
+  trans := NewTMemoryBuffer()
+  p := NewTSimpleJSONProtocol(trans)
+  if e := p.WriteBinary(value); e != nil {
+    t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+  }
+  if e := p.Flush(); e != nil {
+    t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+  }
+  s := trans.String()
+  if s != fmt.Sprint("\"", b64String, "\"") {
+    t.Fatalf("Bad value for %s %v\n  wrote: %v\nexpected: %v", thetype, value, s, "\""+b64String+"\"")
+  }
+  v1 := new(string)
+  if err := json.Unmarshal([]byte(s), v1); err != nil || *v1 != b64String {
+    t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, *v1)
+  }
+  trans.Close()
+}
+
+func TestReadSimpleJSONProtocolBinary(t *testing.T) {
+  thetype := "binary"
+  value := protocol_bdata
+  b64value := make([]byte, base64.StdEncoding.EncodedLen(len(protocol_bdata)))
+  base64.StdEncoding.Encode(b64value, value)
+  b64String := string(b64value)
+  trans := NewTMemoryBuffer()
+  p := NewTSimpleJSONProtocol(trans)
+  trans.WriteString(JsonQuote(b64String))
+  trans.Flush()
+  s := trans.String()
+  v, e := p.ReadBinary()
+  if e != nil {
+    t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+  }
+  if len(v) != len(value) {
+    t.Fatalf("Bad value for %s value length %v, wrote: %v, received length: %v", thetype, len(value), s, len(v))
+  }
+  for i := 0; i < len(v); i++ {
+    if v[i] != value[i] {
+      t.Fatalf("Bad value for %s at index %d value %v, wrote: %v, received: %v", thetype, i, value[i], s, v[i])
+    }
+  }
+  v1 := new(string)
+  if err := json.Unmarshal([]byte(s), v1); err != nil || *v1 != b64String {
+    t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, *v1)
+  }
+  trans.Reset()
+  trans.Close()
+}
+
+func TestWriteSimpleJSONProtocolList(t *testing.T) {
+  thetype := "list"
+  trans := NewTMemoryBuffer()
+  p := NewTSimpleJSONProtocol(trans)
+  p.WriteListBegin(TType(DOUBLE), len(DOUBLE_VALUES))
+  for _, value := range DOUBLE_VALUES {
+    if e := p.WriteDouble(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+  }
+  p.WriteListEnd()
+  if e := p.Flush(); e != nil {
+    t.Fatalf("Unable to write %s due to error flushing: %s", thetype, e.String())
+  }
+  str := trans.String()
+  str1 := new([]interface{})
+  err := json.Unmarshal([]byte(str), str1)
+  if err != nil {
+    t.Fatalf("Unable to decode %s, wrote: %s", thetype, str)
+  }
+  l := *str1
+  if len(l) < 2 {
+    t.Fatalf("List must be at least of length two to include metadata")
+  }
+  if int(l[0].(float64)) != DOUBLE {
+    t.Fatal("Invalid type for list, expected: ", DOUBLE, ", but was: ", l[0])
+  }
+  if int(l[1].(float64)) != len(DOUBLE_VALUES) {
+    t.Fatal("Invalid length for list, expected: ", len(DOUBLE_VALUES), ", but was: ", l[1])
+  }
+  for k, value := range DOUBLE_VALUES {
+    s := l[k+2]
+    if math.IsInf(value, 1) {
+      if s.(string) != JSON_INFINITY {
+        t.Fatalf("Bad value for %s at index %v %v, wrote: %q, expected: %q, originally wrote: %q", thetype, k, value, s, JsonQuote(JSON_INFINITY), str)
+      }
+    } else if math.IsInf(value, 0) {
+      if s.(string) != JSON_NEGATIVE_INFINITY {
+        t.Fatalf("Bad value for %s at index %v %v, wrote: %q, expected: %q, originally wrote: %q", thetype, k, value, s, JsonQuote(JSON_NEGATIVE_INFINITY), str)
+      }
+    } else if math.IsNaN(value) {
+      if s.(string) != JSON_NAN {
+        t.Fatalf("Bad value for %s at index %v  %v, wrote: %q, expected: %q, originally wrote: %q", thetype, k, value, s, JsonQuote(JSON_NAN), str)
+      }
+    } else {
+      if s.(float64) != value {
+        t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s'", thetype, value, s)
+      }
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestWriteSimpleJSONProtocolSet(t *testing.T) {
+  thetype := "set"
+  trans := NewTMemoryBuffer()
+  p := NewTSimpleJSONProtocol(trans)
+  p.WriteSetBegin(TType(DOUBLE), len(DOUBLE_VALUES))
+  for _, value := range DOUBLE_VALUES {
+    if e := p.WriteDouble(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+  }
+  p.WriteSetEnd()
+  if e := p.Flush(); e != nil {
+    t.Fatalf("Unable to write %s due to error flushing: %s", thetype, e.String())
+  }
+  str := trans.String()
+  str1 := new([]interface{})
+  err := json.Unmarshal([]byte(str), str1)
+  if err != nil {
+    t.Fatalf("Unable to decode %s, wrote: %s", thetype, str)
+  }
+  l := *str1
+  if len(l) < 2 {
+    t.Fatalf("Set must be at least of length two to include metadata")
+  }
+  if int(l[0].(float64)) != DOUBLE {
+    t.Fatal("Invalid type for set, expected: ", DOUBLE, ", but was: ", l[0])
+  }
+  if int(l[1].(float64)) != len(DOUBLE_VALUES) {
+    t.Fatal("Invalid length for set, expected: ", len(DOUBLE_VALUES), ", but was: ", l[1])
+  }
+  for k, value := range DOUBLE_VALUES {
+    s := l[k+2]
+    if math.IsInf(value, 1) {
+      if s.(string) != JSON_INFINITY {
+        t.Fatalf("Bad value for %s at index %v %v, wrote: %q, expected: %q, originally wrote: %q", thetype, k, value, s, JsonQuote(JSON_INFINITY), str)
+      }
+    } else if math.IsInf(value, 0) {
+      if s.(string) != JSON_NEGATIVE_INFINITY {
+        t.Fatalf("Bad value for %s at index %v %v, wrote: %q, expected: %q, originally wrote: %q", thetype, k, value, s, JsonQuote(JSON_NEGATIVE_INFINITY), str)
+      }
+    } else if math.IsNaN(value) {
+      if s.(string) != JSON_NAN {
+        t.Fatalf("Bad value for %s at index %v  %v, wrote: %q, expected: %q, originally wrote: %q", thetype, k, value, s, JsonQuote(JSON_NAN), str)
+      }
+    } else {
+      if s.(float64) != value {
+        t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s'", thetype, value, s)
+      }
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestWriteSimpleJSONProtocolMap(t *testing.T) {
+  thetype := "map"
+  trans := NewTMemoryBuffer()
+  p := NewTSimpleJSONProtocol(trans)
+  p.WriteMapBegin(TType(I32), TType(DOUBLE), len(DOUBLE_VALUES))
+  for k, value := range DOUBLE_VALUES {
+    if e := p.WriteI32(int32(k)); e != nil {
+      t.Fatalf("Unable to write %s key int32 value %v due to error: %s", thetype, k, e.String())
+    }
+    if e := p.WriteDouble(value); e != nil {
+      t.Fatalf("Unable to write %s value float64 value %v due to error: %s", thetype, value, e.String())
+    }
+  }
+  p.WriteMapEnd()
+  if e := p.Flush(); e != nil {
+    t.Fatalf("Unable to write %s due to error flushing: %s", thetype, e.String())
+  }
+  str := trans.String()
+  if str[0] != '[' || str[len(str)-1] != ']' {
+    t.Fatalf("Bad value for %s, wrote: %q, in go: %q", thetype, str, DOUBLE_VALUES)
+  }
+  l := strings.Split(str[1:len(str)-1], ",", -1)
+  if len(l) < 3 {
+    t.Fatal("Expected list of at least length 3 for map for metadata, but was of length ", len(l))
+  }
+  expectedKeyType, _ := strconv.Atoi(l[0])
+  expectedValueType, _ := strconv.Atoi(l[1])
+  expectedSize, _ := strconv.Atoi(l[2])
+  if expectedKeyType != I32 {
+    t.Fatal("Expected map key type ", I32, ", but was ", l[0])
+  }
+  if expectedValueType != DOUBLE {
+    t.Fatal("Expected map value type ", DOUBLE, ", but was ", l[1])
+  }
+  if expectedSize != len(DOUBLE_VALUES) {
+    t.Fatal("Expected map size of ", len(DOUBLE_VALUES), ", but was ", l[2])
+  }
+  for k, value := range DOUBLE_VALUES {
+    strk := l[k*2+3]
+    strv := l[k*2+4]
+    ik, err := strconv.Atoi(strk)
+    if err != nil {
+      t.Fatalf("Bad value for %s index %v, wrote: %v, expected: %v, error: %s", thetype, k, strk, string(k), err.String())
+    }
+    if ik != k {
+      t.Fatalf("Bad value for %s index %v, wrote: %v, expected: %v", thetype, k, strk, k)
+    }
+    s := strv
+    if math.IsInf(value, 1) {
+      if s != JsonQuote(JSON_INFINITY) {
+        t.Fatalf("Bad value for %s at index %v %v, wrote: %v, expected: %v", thetype, k, value, s, JsonQuote(JSON_INFINITY))
+      }
+    } else if math.IsInf(value, 0) {
+      if s != JsonQuote(JSON_NEGATIVE_INFINITY) {
+        t.Fatalf("Bad value for %s at index %v %v, wrote: %v, expected: %v", thetype, k, value, s, JsonQuote(JSON_NEGATIVE_INFINITY))
+      }
+    } else if math.IsNaN(value) {
+      if s != JsonQuote(JSON_NAN) {
+        t.Fatalf("Bad value for %s at index %v  %v, wrote: %v, expected: %v", thetype, k, value, s, JsonQuote(JSON_NAN))
+      }
+    } else {
+      expected := strconv.Ftoa64(value, 'g', 10)
+      if s != expected {
+        t.Fatalf("Bad value for %s at index %v %v, wrote: %v, expected %v", thetype, k, value, s, expected)
+      }
+      v := float64(0)
+      if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+        t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+      }
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+
+func TestReadWriteSimpleJSONStruct(t *testing.T) {
+  thetype := "struct"
+  trans := NewTMemoryBuffer()
+  p := NewTSimpleJSONProtocol(trans)
+  orig := NewWork()
+  orig.Num1 = 25
+  orig.Num2 = 102
+  orig.Op = ADD
+  orig.Comment = "Add: 25 + 102"
+  if e := orig.Write(p); e != nil {
+    t.Fatalf("Unable to write %s value %#v due to error: %s", thetype, orig, e.String())
+  }
+  t.Log("Memory buffer contents: ", trans.String())
+  read := NewWork()
+  e := read.Read(p)
+  t.Logf("Read %s value: %#v", thetype, read)
+  if e != nil {
+    t.Fatalf("Unable to read %s due to error: %s", thetype, e.String())
+  }
+  if !orig.Equals(read) {
+    t.Fatalf("Original Write != Read: %#v != %#v ", orig, read)
+  }
+}
+
+func TestReadWriteSimpleJSONProtocol(t *testing.T) {
+  ReadWriteProtocolTest(t, NewTSimpleJSONProtocolFactory())
+}
diff --git a/lib/go/thrift/tsimple_server.go b/lib/go/thrift/tsimple_server.go
new file mode 100644
index 0000000..6c7d656
--- /dev/null
+++ b/lib/go/thrift/tsimple_server.go
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "os"
+)
+
+
+/**
+ * Simple singlethreaded server for testing.
+ *
+ */
+type TSimpleServer struct {
+  stopped bool
+
+  processorFactory       TProcessorFactory
+  serverTransport        TServerTransport
+  inputTransportFactory  TTransportFactory
+  outputTransportFactory TTransportFactory
+  inputProtocolFactory   TProtocolFactory
+  outputProtocolFactory  TProtocolFactory
+}
+
+func NewTSimpleServer2(processor TProcessor, serverTransport TServerTransport) *TSimpleServer {
+  return NewTSimpleServerFactory2(NewTProcessorFactory(processor), serverTransport)
+}
+
+func NewTSimpleServer4(processor TProcessor, serverTransport TServerTransport, transportFactory TTransportFactory, protocolFactory TProtocolFactory) *TSimpleServer {
+  return NewTSimpleServerFactory4(NewTProcessorFactory(processor),
+    serverTransport,
+    transportFactory,
+    protocolFactory,
+  )
+}
+
+func NewTSimpleServer6(processor TProcessor, serverTransport TServerTransport, inputTransportFactory TTransportFactory, outputTransportFactory TTransportFactory, inputProtocolFactory TProtocolFactory, outputProtocolFactory TProtocolFactory) *TSimpleServer {
+  return NewTSimpleServerFactory6(NewTProcessorFactory(processor),
+    serverTransport,
+    inputTransportFactory,
+    outputTransportFactory,
+    inputProtocolFactory,
+    outputProtocolFactory,
+  )
+}
+
+func NewTSimpleServerFactory2(processorFactory TProcessorFactory, serverTransport TServerTransport) *TSimpleServer {
+  return NewTSimpleServerFactory6(processorFactory,
+    serverTransport,
+    NewTTransportFactory(),
+    NewTTransportFactory(),
+    NewTBinaryProtocolFactoryDefault(),
+    NewTBinaryProtocolFactoryDefault(),
+  )
+}
+
+func NewTSimpleServerFactory4(processorFactory TProcessorFactory, serverTransport TServerTransport, transportFactory TTransportFactory, protocolFactory TProtocolFactory) *TSimpleServer {
+  return NewTSimpleServerFactory6(processorFactory,
+    serverTransport,
+    transportFactory,
+    transportFactory,
+    protocolFactory,
+    protocolFactory,
+  )
+}
+
+func NewTSimpleServerFactory6(processorFactory TProcessorFactory, serverTransport TServerTransport, inputTransportFactory TTransportFactory, outputTransportFactory TTransportFactory, inputProtocolFactory TProtocolFactory, outputProtocolFactory TProtocolFactory) *TSimpleServer {
+  return &TSimpleServer{processorFactory: processorFactory,
+    serverTransport:        serverTransport,
+    inputTransportFactory:  inputTransportFactory,
+    outputTransportFactory: outputTransportFactory,
+    inputProtocolFactory:   inputProtocolFactory,
+    outputProtocolFactory:  outputProtocolFactory,
+  }
+}
+
+func (p *TSimpleServer) ProcessorFactory() TProcessorFactory {
+  return p.processorFactory
+}
+
+func (p *TSimpleServer) ServerTransport() TServerTransport {
+  return p.serverTransport
+}
+
+func (p *TSimpleServer) InputTransportFactory() TTransportFactory {
+  return p.inputTransportFactory
+}
+
+func (p *TSimpleServer) OutputTransportFactory() TTransportFactory {
+  return p.outputTransportFactory
+}
+
+func (p *TSimpleServer) InputProtocolFactory() TProtocolFactory {
+  return p.inputProtocolFactory
+}
+
+func (p *TSimpleServer) OutputProtocolFactory() TProtocolFactory {
+  return p.outputProtocolFactory
+}
+
+func (p *TSimpleServer) Serve() os.Error {
+  p.stopped = false
+  err := p.serverTransport.Listen()
+  if err != nil {
+    return err
+  }
+  for !p.stopped {
+    client, err := p.serverTransport.Accept()
+    if err != nil {
+      return err
+    }
+    if client != nil {
+      p.processRequest(client)
+    }
+  }
+  return nil
+}
+
+func (p *TSimpleServer) Stop() os.Error {
+  p.stopped = true
+  p.serverTransport.Interrupt()
+  return nil
+}
+
+func (p *TSimpleServer) processRequest(client TTransport) {
+  processor := p.processorFactory.GetProcessor(client)
+  inputTransport := p.inputTransportFactory.GetTransport(client)
+  outputTransport := p.outputTransportFactory.GetTransport(client)
+  inputProtocol := p.inputProtocolFactory.GetProtocol(inputTransport)
+  outputProtocol := p.outputProtocolFactory.GetProtocol(outputTransport)
+  if inputTransport != nil {
+    defer inputTransport.Close()
+  }
+  if outputTransport != nil {
+    defer outputTransport.Close()
+  }
+  for {
+    ok, e := processor.Process(inputProtocol, outputProtocol)
+    if e != nil {
+      if !p.stopped {
+        // TODO(pomack) log error
+        break
+      }
+    }
+    if !ok {
+      break
+    }
+  }
+}
diff --git a/lib/go/thrift/tsocket.go b/lib/go/thrift/tsocket.go
new file mode 100644
index 0000000..758c132
--- /dev/null
+++ b/lib/go/thrift/tsocket.go
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "net"
+  "os"
+  "bytes"
+)
+
+/**
+ * Socket implementation of the TTransport interface. To be commented soon!
+ *
+ */
+type TSocket struct {
+  writeBuffer *bytes.Buffer
+  /**
+   * Wrapped Socket object
+   */
+  conn net.Conn
+  /**
+   * Remote Addr
+   */
+  addr net.Addr
+  /**
+   * Socket timeout in nanoseconds
+   */
+  nsecTimeout int64
+}
+
+/**
+ * Constructor that takes an already created socket.
+ *
+ * @param socket Already created socket object
+ * @throws TTransportException if there is an error setting up the streams
+ */
+func NewTSocketConn(connection net.Conn) (*TSocket, TTransportException) {
+  address := connection.RemoteAddr()
+  if address == nil {
+    address = connection.LocalAddr()
+  }
+  p := &TSocket{conn: connection, addr: address, nsecTimeout: 0, writeBuffer: bytes.NewBuffer(make([]byte, 0, 4096))}
+  return p, nil
+}
+
+/**
+ * Creates a new unconnected socket that will connect to the given host
+ * on the given port.
+ *
+ * @param host Remote host
+ * @param port Remote port
+ */
+func NewTSocketAddr(address net.Addr) *TSocket {
+  return NewTSocket(address, 0)
+}
+
+/**
+ * Creates a new unconnected socket that will connect to the given host
+ * on the given port.
+ *
+ * @param host    Remote host
+ * @param port    Remote port
+ * @param nsecTimeout Socket timeout
+ */
+func NewTSocket(address net.Addr, nsecTimeout int64) *TSocket {
+  sock := &TSocket{addr: address, nsecTimeout: nsecTimeout, writeBuffer: bytes.NewBuffer(make([]byte, 0, 4096))}
+  return sock
+}
+
+/**
+ * Sets the socket timeout
+ *
+ * @param timeout Nanoseconds timeout
+ */
+func (p *TSocket) SetTimeout(nsecTimeout int64) os.Error {
+  p.nsecTimeout = nsecTimeout
+  if p.IsOpen() {
+    if err := p.conn.SetTimeout(nsecTimeout); err != nil {
+      LOGGER.Print("Could not set socket timeout.", err)
+      return err
+    }
+  }
+  return nil
+}
+
+/**
+ * Returns a reference to the underlying socket.
+ */
+func (p *TSocket) Conn() net.Conn {
+  return p.conn
+}
+
+/**
+ * Checks whether the socket is connected.
+ */
+func (p *TSocket) IsOpen() bool {
+  if p.conn == nil {
+    return false
+  }
+  return true
+}
+
+/**
+ * Connects the socket, creating a new socket object if necessary.
+ */
+func (p *TSocket) Open() os.Error {
+  if p.IsOpen() {
+    return NewTTransportException(ALREADY_OPEN, "Socket already connected.")
+  }
+  if p.addr == nil {
+    return NewTTransportException(NOT_OPEN, "Cannot open nil address.")
+  }
+  if len(p.addr.Network()) == 0 {
+    return NewTTransportException(NOT_OPEN, "Cannot open bad network name.")
+  }
+  if len(p.addr.String()) == 0 {
+    return NewTTransportException(NOT_OPEN, "Cannot open bad address.")
+  }
+  var err os.Error
+  if p.conn, err = net.Dial(p.addr.Network(), "", p.addr.String()); err != nil {
+    LOGGER.Print("Could not open socket", err.String())
+    return NewTTransportException(NOT_OPEN, err.String())
+  }
+  if p.conn != nil {
+    p.conn.SetTimeout(p.nsecTimeout)
+  }
+  return nil
+}
+
+/**
+ * Closes the socket.
+ */
+func (p *TSocket) Close() os.Error {
+  // Close the socket
+  if p.conn != nil {
+    err := p.conn.Close()
+    if err != nil {
+      LOGGER.Print("Could not close socket. ", err.String())
+      return err
+    }
+    p.conn = nil
+  }
+  return nil
+}
+
+
+func (p *TSocket) Read(buf []byte) (int, os.Error) {
+  if !p.IsOpen() {
+    return 0, NewTTransportException(NOT_OPEN, "Connection not open")
+  }
+  n, err := p.conn.Read(buf)
+  return n, NewTTransportExceptionFromOsError(err)
+}
+
+
+func (p *TSocket) ReadAll(buf []byte) (int, os.Error) {
+  return ReadAllTransport(p, buf)
+}
+
+func (p *TSocket) Write(buf []byte) (int, os.Error) {
+  if !p.IsOpen() {
+    return 0, NewTTransportException(NOT_OPEN, "Connection not open")
+  }
+  p.writeBuffer.Write(buf)
+  return len(buf), nil
+}
+
+func (p *TSocket) Peek() bool {
+  return p.IsOpen()
+}
+
+func (p *TSocket) Flush() os.Error {
+  if !p.IsOpen() {
+    return NewTTransportException(NOT_OPEN, "Connection not open")
+  }
+  _, err := p.writeBuffer.WriteTo(p.conn)
+  return NewTTransportExceptionFromOsError(err)
+}
+
+func (p *TSocket) Interrupt() os.Error {
+  if !p.IsOpen() {
+    return nil
+  }
+  // TODO(pomack) fix Interrupt as this is probably wrong
+  return p.conn.Close()
+}
diff --git a/lib/go/thrift/tstruct.go b/lib/go/thrift/tstruct.go
new file mode 100644
index 0000000..5eaffae
--- /dev/null
+++ b/lib/go/thrift/tstruct.go
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+/**
+ * Helper class that encapsulates struct metadata.
+ *
+ */
+type TStruct interface {
+  TFieldContainer
+  TStructName() string
+  ThriftName() string
+  TStructFields() TFieldContainer
+  String() string
+  AttributeFromFieldId(fieldId int) interface{}
+  AttributeFromFieldName(fieldName string) interface{}
+}
+
+type tStruct struct {
+  TFieldContainer
+  name string
+}
+
+func NewTStructEmpty(name string) TStruct {
+  return &tStruct{
+    name:            name,
+    TFieldContainer: NewTFieldContainer(make([]TField, 0, 0)),
+  }
+}
+
+func NewTStruct(name string, fields []TField) TStruct {
+  return &tStruct{
+    name:            name,
+    TFieldContainer: NewTFieldContainer(fields),
+  }
+}
+
+func (p *tStruct) TStructName() string {
+  return p.name
+}
+
+func (p *tStruct) ThriftName() string {
+  return p.name
+}
+
+func (p *tStruct) TStructFields() TFieldContainer {
+  return p.TFieldContainer
+}
+
+func (p *tStruct) String() string {
+  return p.name
+}
+
+func (p *tStruct) Equals(other interface{}) bool {
+  cmp, ok := p.CompareTo(other)
+  return ok && cmp == 0
+}
+
+func (p *tStruct) CompareTo(other interface{}) (int, bool) {
+  return TType(STRUCT).Compare(p, other)
+}
+
+func (p *tStruct) AttributeFromFieldId(fieldId int) interface{} {
+  return nil
+}
+
+func (p *tStruct) AttributeFromFieldName(fieldName string) interface{} {
+  return p.AttributeFromFieldId(p.FieldIdFromFieldName(fieldName))
+}
+
+
+var ANONYMOUS_STRUCT TStruct
+
+func init() {
+  ANONYMOUS_STRUCT = NewTStructEmpty("")
+}
diff --git a/lib/go/thrift/ttransport.go b/lib/go/thrift/ttransport.go
new file mode 100644
index 0000000..45557f8
--- /dev/null
+++ b/lib/go/thrift/ttransport.go
@@ -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.
+ */
+
+package thrift
+
+import (
+  "os"
+  "log"
+)
+
+type Flusher interface {
+  Flush() (err os.Error)
+}
+
+/**
+ * Generic class that encapsulates the I/O layer. This is basically a thin
+ * wrapper around the combined functionality of Java input/output streams.
+ *
+ */
+type TTransport interface {
+  /**
+   * Queries whether the transport is open.
+   *
+   * @return True if the transport is open.
+   */
+  IsOpen() bool
+
+  /**
+   * Opens the transport for reading/writing.
+   *
+   * @returns TTransportException if the transport could not be opened
+   */
+  Open() (err os.Error)
+
+  /**
+   * Closes the transport.
+   */
+  Close() (err os.Error)
+
+  /**
+   * Reads up to len bytes into buffer buf, starting att offset off.
+   *
+   * @param buf Array to read into
+   * @param off Index to start reading at
+   * @param len Maximum number of bytes to read
+   * @return The number of bytes actually read
+   * @return TTransportException if there was an error reading data
+   */
+  Read(buf []byte) (n int, err os.Error)
+
+  /**
+   * Guarantees that all of len bytes are actually read off the transport.
+   *
+   * @param buf Array to read into
+   * @param off Index to start reading at
+   * @param len Maximum number of bytes to read
+   * @return The number of bytes actually read, which must be equal to len
+   * @return TTransportException if there was an error reading data
+   */
+  ReadAll(buf []byte) (n int, err os.Error)
+
+  /**
+   * Writes the buffer to the output
+   *
+   * @param buf The output data buffer
+   * @return Number of bytes written
+   * @return TTransportException if an error occurs writing data
+   */
+  Write(buf []byte) (n int, err os.Error)
+
+  /**
+   * Flush any pending data out of a transport buffer.
+   *
+   * @return TTransportException if there was an error writing out data.
+   */
+  Flush() (err os.Error)
+
+  /**
+   * Is there more data to be read?
+   *
+   * @return True if the remote side is still alive and feeding us
+   */
+  Peek() bool
+}
+/*
+type TTransportBase struct {
+}
+
+func (p* TTransportBase) IsOpen() bool {
+  return false;
+};
+
+func (p* TTransportBase) Peek() bool {
+  return p.IsOpen();
+}
+
+func (p* TTransportBase) Open() os.Error {
+  return NewTTransportException(UNKNOWN, "Subclasses must implement TTransportBase.Open()");
+}
+
+func (p* TTransportBase) Close() os.Error {
+  return NewTTransportException(UNKNOWN, "Subclasses must implement TTransportBase.Close()");
+}
+
+func (p* TTransportBase) Read(buf []byte) (int, os.Error) {
+  return 0, NewTTransportExceptionDefaultString("Subclasses must implement TTransportBase.Read()");
+}
+
+func (p* TTransportBase) ReadAll(buf []byte) (n int, err os.Error){
+  ret := 0;
+  size := len(buf);
+  for (n < size) {
+    ret, err = p.Read(buf[n:]);
+    if ret <= 0 {
+      if err != nil {
+        err = NewTTransportExceptionDefaultString("Cannot read. Remote side has closed. Tried to read " + string(size) + " bytes, but only got " + string(n) + " bytes.");
+      }
+      return ret, err;
+    }
+    n += ret;
+  }
+  return n, err;
+}
+
+func (p* TTransportBase) Write(buf []byte) (int, os.Error) {
+  return 0, NewTTransportExceptionDefaultString("Subclasses must implement TTransportBase.Write()");
+}
+
+func (p* TTransportBase) Flush() os.Error {
+  return nil;
+}
+*/
+/**
+ * Guarantees that all of len bytes are actually read off the transport.
+ *
+ * @param buf Array to read into
+ * @param off Index to start reading at
+ * @param len Maximum number of bytes to read
+ * @return The number of bytes actually read, which must be equal to len
+ * @return TTransportException if there was an error reading data
+ */
+func ReadAllTransport(p TTransport, buf []byte) (n int, err os.Error) {
+  ret := 0
+  size := len(buf)
+  for n < size {
+    ret, err = p.Read(buf[n:])
+    if ret <= 0 {
+      if err != nil {
+        err = NewTTransportExceptionDefaultString("Cannot read. Remote side has closed. Tried to read " + string(size) + " bytes, but only got " + string(n) + " bytes.")
+      }
+      return ret, err
+    }
+    n += ret
+  }
+  return n, err
+}
+
+
+var (
+  LOGGER *log.Logger
+)
+
+func init() {
+  LOGGER = log.New(os.Stderr, "", log.Ldate|log.Ltime|log.Lshortfile)
+}
diff --git a/lib/go/thrift/ttransport_exception.go b/lib/go/thrift/ttransport_exception.go
new file mode 100644
index 0000000..b9fae17
--- /dev/null
+++ b/lib/go/thrift/ttransport_exception.go
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+  "os"
+)
+
+/**
+ * Transport exceptions.
+ *
+ */
+type TTransportException interface {
+  TException
+  TypeId() int
+}
+
+const (
+  UNKNOWN_TRANSPORT_EXCEPTION = 0
+  NOT_OPEN                    = 1
+  ALREADY_OPEN                = 2
+  TIMED_OUT                   = 3
+  END_OF_FILE                 = 4
+)
+
+type tTransportException struct {
+  typeId  int
+  message string
+}
+
+func (p *tTransportException) TypeId() int {
+  return p.typeId
+}
+
+func (p *tTransportException) String() string {
+  return p.message
+}
+
+func NewTTransportExceptionDefault() TTransportException {
+  return NewTTransportExceptionDefaultType(UNKNOWN_TRANSPORT_EXCEPTION)
+}
+
+func NewTTransportExceptionDefaultType(t int) TTransportException {
+  return NewTTransportException(t, "")
+}
+
+func NewTTransportExceptionDefaultString(m string) TTransportException {
+  return NewTTransportException(UNKNOWN_TRANSPORT_EXCEPTION, m)
+}
+
+func NewTTransportException(t int, m string) TTransportException {
+  return &tTransportException{typeId: t, message: m}
+}
+
+func NewTTransportExceptionFromOsError(e os.Error) TTransportException {
+  if e == nil {
+    return nil
+  }
+  t, ok := e.(TTransportException)
+  if ok {
+    return t
+  }
+  if e == os.EOF {
+    return NewTTransportException(END_OF_FILE, e.String())
+  }
+  return NewTTransportExceptionDefaultString(e.String())
+}
diff --git a/lib/go/thrift/ttransport_factory.go b/lib/go/thrift/ttransport_factory.go
new file mode 100644
index 0000000..4ab4dbe
--- /dev/null
+++ b/lib/go/thrift/ttransport_factory.go
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package thrift
+
+/**
+ * Factory class used to create wrapped instance of Transports.
+ * This is used primarily in servers, which get Transports from
+ * a ServerTransport and then may want to mutate them (i.e. create
+ * a BufferedTransport from the underlying base transport)
+ *
+ */
+type TTransportFactory interface {
+  GetTransport(trans TTransport) TTransport
+}
+
+type tTransportFactory struct{}
+
+/**
+ * Return a wrapped instance of the base Transport.
+ *
+ * @param trans The base transport
+ * @return Wrapped Transport
+ */
+func (p *tTransportFactory) GetTransport(trans TTransport) TTransport {
+  return trans
+}
+
+func NewTTransportFactory() TTransportFactory {
+  return &tTransportFactory{}
+}
diff --git a/lib/go/thrift/ttransport_test.go b/lib/go/thrift/ttransport_test.go
new file mode 100644
index 0000000..b9630de
--- /dev/null
+++ b/lib/go/thrift/ttransport_test.go
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+package thrift_test
+
+import (
+  . "thrift"
+  "testing"
+  "net"
+  "os"
+  "strconv"
+)
+
+const TRANSPORT_BINARY_DATA_SIZE = 4096
+
+var (
+  transport_bdata []byte // test data for writing; same as data
+)
+
+func init() {
+  transport_bdata = make([]byte, TRANSPORT_BINARY_DATA_SIZE)
+  for i := 0; i < TRANSPORT_BINARY_DATA_SIZE; i++ {
+    transport_bdata[i] = byte((i + 'a') % 255)
+  }
+}
+
+func TransportTest(t *testing.T, writeTrans TTransport, readTrans TTransport) {
+  buf := make([]byte, TRANSPORT_BINARY_DATA_SIZE)
+  if !writeTrans.IsOpen() {
+    err := writeTrans.Open()
+    if err != nil {
+      t.Fatalf("Transport %T cannot open write transport: %s", writeTrans, err)
+    }
+  }
+  if !readTrans.IsOpen() {
+    err := readTrans.Open()
+    if err != nil {
+      t.Fatalf("Transport %T cannot open read transport: %s", readTrans, err)
+    }
+  }
+  _, err := writeTrans.Write(transport_bdata)
+  if err != nil {
+    t.Fatalf("Transport %T cannot write binary data of length %d: %s", writeTrans, len(transport_bdata), err)
+  }
+  err = writeTrans.Flush()
+  if err != nil {
+    t.Fatalf("Transport %T cannot flush write of binary data: %s", writeTrans, err)
+  }
+  n, err := readTrans.ReadAll(buf)
+  if err != nil {
+    t.Errorf("Transport %T cannot read binary data of length %d: %s", readTrans, TRANSPORT_BINARY_DATA_SIZE, err)
+  }
+  if n != TRANSPORT_BINARY_DATA_SIZE {
+    t.Errorf("Transport %T read only %d instead of %d bytes of binary data", readTrans, n, TRANSPORT_BINARY_DATA_SIZE)
+  }
+  for k, v := range buf {
+    if v != transport_bdata[k] {
+      t.Fatalf("Transport %T read %d instead of %d for index %d of binary data 2", readTrans, v, transport_bdata[k], k)
+    }
+  }
+  _, err = writeTrans.Write(transport_bdata)
+  if err != nil {
+    t.Fatalf("Transport %T cannot write binary data 2 of length %d: %s", writeTrans, len(transport_bdata), err)
+  }
+  err = writeTrans.Flush()
+  if err != nil {
+    t.Fatalf("Transport %T cannot flush write binary data 2: %s", writeTrans, err)
+  }
+  b := readTrans.Peek()
+  if b != true {
+    t.Errorf("Transport %T returned %s for Peek()", readTrans, b)
+  }
+  buf = make([]byte, TRANSPORT_BINARY_DATA_SIZE)
+  read := 1
+  for n = 0; n < TRANSPORT_BINARY_DATA_SIZE && read != 0; {
+    read, err = readTrans.Read(buf[n:])
+    if err != nil {
+      t.Errorf("Transport %T cannot read binary data 2 of total length %d from offset %d: %s", readTrans, TRANSPORT_BINARY_DATA_SIZE, n, err)
+    }
+    n += read
+  }
+  if n != TRANSPORT_BINARY_DATA_SIZE {
+    t.Errorf("Transport %T read only %d instead of %d bytes of binary data 2", readTrans, n, TRANSPORT_BINARY_DATA_SIZE)
+  }
+  for k, v := range buf {
+    if v != transport_bdata[k] {
+      t.Fatalf("Transport %T read %d instead of %d for index %d of binary data 2", readTrans, v, transport_bdata[k], k)
+    }
+  }
+}
+
+func CloseTransports(t *testing.T, readTrans TTransport, writeTrans TTransport) {
+  err := readTrans.Close()
+  if err != nil {
+    t.Errorf("Transport %T cannot close read transport: %s", readTrans, err)
+  }
+  if writeTrans != readTrans {
+    err = writeTrans.Close()
+    if err != nil {
+      t.Errorf("Transport %T cannot close write transport: %s", writeTrans, err)
+    }
+  }
+}
+
+func FindAvailableTCPServerPort(startPort int) (net.Addr, os.Error) {
+  for i := startPort; i < 65535; i++ {
+    s := "127.0.0.1:" + strconv.Itoa(i)
+    l, err := net.Listen("tcp", s)
+    if err == nil {
+      l.Close()
+      return net.ResolveTCPAddr(s)
+    }
+  }
+  return nil, NewTTransportException(UNKNOWN_TRANSPORT_EXCEPTION, "Could not find available server port")
+}
diff --git a/lib/go/thrift/ttype.go b/lib/go/thrift/ttype.go
new file mode 100644
index 0000000..d024b39
--- /dev/null
+++ b/lib/go/thrift/ttype.go
@@ -0,0 +1,975 @@
+/*
+ * 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.
+ */
+
+
+package thrift
+
+import (
+  "container/list"
+  "container/vector"
+  "strconv"
+)
+
+/**
+ * Type constants in the Thrift protocol.
+ */
+type TType byte
+
+const (
+  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
+  ENUM    = 16
+  UTF8    = 16
+  UTF16   = 17
+  GENERIC = 127
+)
+
+func (p TType) String() string {
+  switch p {
+  case STOP:
+    return "STOP"
+  case VOID:
+    return "VOID"
+  case BOOL:
+    return "BOOL"
+  case BYTE:
+    return "BYTE"
+  case DOUBLE:
+    return "DOUBLE"
+  case I16:
+    return "I16"
+  case I32:
+    return "I32"
+  case I64:
+    return "I64"
+  case STRING:
+    return "STRING"
+  case STRUCT:
+    return "STRUCT"
+  case MAP:
+    return "MAP"
+  case SET:
+    return "SET"
+  case LIST:
+    return "LIST"
+  case ENUM:
+    return "ENUM"
+  case UTF16:
+    return "UTF16"
+  case GENERIC:
+    return "GENERIC"
+  }
+  return "Unknown"
+}
+
+func (p TType) IsBaseType() bool {
+  switch p {
+  case BOOL, BYTE, DOUBLE, I16, I32, I64, STRING, UTF8, UTF16:
+    return true
+  default:
+    return false
+  }
+  return false
+}
+
+func (p TType) IsEmptyType() bool {
+  switch p {
+  case STOP, VOID:
+    return true
+  default:
+    return false
+  }
+  return false
+}
+
+func (p TType) IsEnum() bool {
+  switch p {
+  case ENUM:
+    return true
+  default:
+    return false
+  }
+  return false
+}
+
+func (p TType) IsNumericType() bool {
+  switch p {
+  case ENUM, BOOL, BYTE, DOUBLE, I16, I32, I64:
+    return true
+  default:
+    return false
+  }
+  return false
+}
+
+func (p TType) IsStringType() bool {
+  switch p {
+  case STRING, UTF8, UTF16:
+    return true
+  default:
+    return false
+  }
+  return false
+}
+
+func (p TType) IsContainer() bool {
+  switch p {
+  case MAP, SET, LIST:
+    return true
+  default:
+    return false
+  }
+  return false
+}
+
+func (p TType) IsStruct() bool {
+  switch p {
+  case STRUCT:
+    return true
+  default:
+    return false
+  }
+  return false
+}
+
+func (p TType) IsMap() bool {
+  switch p {
+  case MAP:
+    return true
+  default:
+    return false
+  }
+  return false
+}
+
+func (p TType) IsList() bool {
+  switch p {
+  case LIST:
+    return true
+  default:
+    return false
+  }
+  return false
+}
+
+func (p TType) IsSet() bool {
+  switch p {
+  case SET:
+    return true
+  default:
+    return false
+  }
+  return false
+}
+
+func (p TType) IsInt() bool {
+  switch p {
+  case BYTE, I16, I32, I64:
+    return true
+  default:
+    return false
+  }
+  return false
+}
+
+func (p TType) Coerce(other interface{}) TType {
+  if other == nil {
+    return TType(STOP)
+  }
+  switch b := other.(type) {
+  default:
+    return TType(STOP)
+  case nil:
+    return TType(STOP)
+  case TType:
+    return b
+  case byte:
+    return TType(b)
+  case int:
+    return TType(byte(b))
+  case int8:
+    return TType(byte(b))
+  case int32:
+    return TType(byte(b))
+  case int64:
+    return TType(byte(b))
+  case uint:
+    return TType(byte(b))
+  case uint32:
+    return TType(byte(b))
+  case uint64:
+    return TType(byte(b))
+  case float32:
+    return TType(byte(int(b)))
+  case float64:
+    return TType(byte(int(b)))
+  }
+  return TType(STOP)
+}
+
+func (p TType) LessType(other interface{}) bool {
+  return p < p.Coerce(other)
+}
+
+func (p TType) Less(i, j interface{}) bool {
+  cmp, ok := p.Compare(i, j)
+  return ok && cmp > 0
+}
+
+
+func (p TType) Compare(i, j interface{}) (int, bool) {
+  if i == j {
+    return 0, true
+  }
+  if i == nil {
+    if j == nil {
+      return 0, true
+    }
+    return -1, true
+  }
+  if j == nil {
+    return 1, true
+  }
+  ci, iok := p.CoerceData(i)
+  cj, jok := p.CoerceData(j)
+  if iok && !jok {
+    return 1, true
+  }
+  if !iok && jok {
+    return -1, true
+  }
+  // hopefully this doesn't happen as Compare() would continuously return 0, false
+  if !iok && !jok {
+    return 0, false
+  }
+  if ci == cj {
+    return 0, true
+  }
+  if ci == nil {
+    if cj == nil {
+      return 0, true
+    }
+    return -1, true
+  }
+  if cj == nil {
+    return 1, true
+  }
+  switch p {
+  case STOP, VOID:
+    // hopefully this doesn't happen as Compare() would continuously return 0, false
+    return 0, false
+  case BOOL:
+    vi := ci.(bool)
+    vj := cj.(bool)
+    if vi == vj {
+      return 0, true
+    }
+    if vi == false {
+      return -1, true
+    }
+    return 1, true
+  case BYTE:
+    vi := ci.(byte)
+    vj := cj.(byte)
+    if vi == vj {
+      return 0, true
+    }
+    if vi < vj {
+      return -1, true
+    }
+    return 1, true
+  case DOUBLE:
+    vi := ci.(float64)
+    vj := cj.(float64)
+    if vi == vj {
+      return 0, true
+    }
+    if vi < vj {
+      return -1, true
+    }
+    return 1, true
+  case I16:
+    vi := ci.(int16)
+    vj := cj.(int16)
+    if vi == vj {
+      return 0, true
+    }
+    if vi < vj {
+      return -1, true
+    }
+    return 1, true
+  case I32:
+    vi := ci.(int32)
+    vj := cj.(int32)
+    if vi == vj {
+      return 0, true
+    }
+    if vi < vj {
+      return -1, true
+    }
+    return 1, true
+  case I64:
+    vi := ci.(int64)
+    vj := cj.(int64)
+    if vi == vj {
+      return 0, true
+    }
+    if vi < vj {
+      return -1, true
+    }
+    return 1, true
+  case STRING, UTF8, UTF16:
+    vi := ci.(string)
+    vj := cj.(string)
+    if vi == vj {
+      return 0, true
+    }
+    if vi < vj {
+      return -1, true
+    }
+    return 1, true
+  case STRUCT:
+    si := ci.(TStruct)
+    sj := cj.(TStruct)
+    if cmp := CompareString(si.ThriftName(), sj.ThriftName()); cmp != 0 {
+      return cmp, true
+    }
+    if cmp, ok := si.TStructFields().CompareTo(sj.TStructFields()); !ok || cmp != 0 {
+      return cmp, ok
+    }
+    for field := range si.TStructFields().Iter() {
+      a := si.AttributeFromFieldId(field.Id())
+      b := sj.AttributeFromFieldId(field.Id())
+      if cmp, ok := field.TypeId().Compare(a, b); !ok || cmp != 0 {
+        return cmp, ok
+      }
+    }
+    return 0, true
+  case MAP:
+    mi := ci.(TMap)
+    mj := cj.(TMap)
+    ei := mi.KeyType()
+    if ej := mj.KeyType(); ei != ej {
+      return CompareInt(int(ei), int(ej)), true
+    }
+    if size := mi.Len(); size != mj.Len() {
+      return CompareInt(size, mj.Len()), true
+    }
+    if c, cok := ei.Compare(mi.Keys(), mj.Keys()); c != 0 || !cok {
+      return c, cok
+    }
+    return ei.Compare(mi.Values(), mj.Values())
+  case LIST:
+    li := ci.(TList)
+    lj := cj.(TList)
+    ei := li.ElemType()
+    ej := lj.ElemType()
+    if ei != ej {
+      return CompareInt(int(ei), int(ej)), true
+    }
+    size := li.Len()
+    if size != lj.Len() {
+      return CompareInt(size, lj.Len()), true
+    }
+    for k := 0; k < size; k++ {
+      vi := li.At(k)
+      vj := lj.At(k)
+      c, cok := ei.Compare(vi, vj)
+      if c != 0 || !cok {
+        return c, cok
+      }
+    }
+    return 0, true
+  case SET:
+    li := ci.(TSet)
+    lj := cj.(TSet)
+    ei := li.ElemType()
+    ej := lj.ElemType()
+    if ei != ej {
+      return CompareInt(int(ei), int(ej)), true
+    }
+    size := li.Len()
+    if size != lj.Len() {
+      return CompareInt(size, lj.Len()), true
+    }
+    return ei.Compare(li.Values(), lj.Values())
+  default:
+    panic("Invalid thrift type to coerce")
+  }
+  return 0, false
+}
+
+func (p TType) CompareValueArrays(li, lj []interface{}) (int, bool) {
+  size := len(li)
+  if cmp := CompareInt(size, len(lj)); cmp != 0 {
+    return cmp, true
+  }
+  for i := 0; i < size; i++ {
+    vi := li[i]
+    vj := lj[i]
+    c, cok := p.Compare(vi, vj)
+    if c != 0 || !cok {
+      return c, cok
+    }
+  }
+  return 0, true
+}
+
+func (p TType) Equals(other interface{}) bool {
+  return p == p.Coerce(other)
+}
+
+type Stringer interface {
+  String() string
+}
+
+type Enumer interface {
+  String() string
+  Value() int
+  IsEnum() bool
+}
+
+func TypeFromValue(data interface{}) TType {
+  switch i := data.(type) {
+  default:
+    return STOP
+  case nil:
+    return VOID
+  case bool:
+    return BOOL
+  case float32, float64:
+    return DOUBLE
+  case int, int32:
+    return I32
+  case byte:
+    return BYTE
+  case int8:
+    return I08
+  case int16:
+    return I16
+  case int64:
+    return I64
+  case string:
+    return STRING
+  case TStruct:
+    return STRUCT
+  case TMap:
+    return MAP
+  case TSet:
+    return SET
+  case []interface{}, *list.List, *vector.Vector, TList:
+    return LIST
+  }
+  return STOP
+}
+
+func (p TType) CoerceData(data interface{}) (interface{}, bool) {
+  if data == nil {
+    switch p {
+    case STOP:
+      return nil, true
+    case VOID:
+      return nil, true
+    case BOOL:
+      return false, true
+    case BYTE:
+      return byte(0), true
+    case DOUBLE:
+      return float64(0), true
+    case I16:
+      return int16(0), true
+    case I32:
+      return int32(0), true
+    case I64:
+      return int64(0), true
+    case STRING, UTF8, UTF16:
+      return "", true
+    case STRUCT:
+      return NewTStructEmpty(""), true
+    case MAP:
+      return NewTMapDefault(), true
+    case LIST:
+      return NewTListDefault(), true
+    case SET:
+      return NewTSetDefault(), true
+    default:
+      panic("Invalid thrift type to coerce")
+    }
+  }
+  switch p {
+  case STOP:
+    return nil, true
+  case VOID:
+    return nil, true
+  case BOOL:
+    switch b := data.(type) {
+    default:
+      return false, false
+    case bool:
+      return b, true
+    case Numeric:
+      return bool(b.Int() != 0), true
+    case int:
+      return b != 0, true
+    case byte:
+      return b != 0, true
+    case int8:
+      return b != 0, true
+    case int16:
+      return b != 0, true
+    case int32:
+      return b != 0, true
+    case int64:
+      return b != 0, true
+    case uint:
+      return b != 0, true
+    case uint16:
+      return b != 0, true
+    case uint32:
+      return b != 0, true
+    case uint64:
+      return b != 0, true
+    case float32:
+      return b != 0, true
+    case float64:
+      return b != 0, true
+    case Stringer:
+      v := b.String()
+      if v == "false" || v == "0" || len(v) == 0 {
+        return false, true
+      }
+      return true, true
+    case string:
+      if b == "false" || b == "0" || len(b) == 0 {
+        return false, true
+      }
+      return true, true
+    }
+  case BYTE:
+    if b, ok := data.(byte); ok {
+      return b, true
+    }
+    if b, ok := data.(Numeric); ok {
+      return b.Byte(), true
+    }
+    if b, ok := data.(bool); ok {
+      if b {
+        return byte(1), true
+      }
+      return byte(0), true
+    }
+    if b, ok := data.(int); ok {
+      return byte(b), true
+    }
+    if b, ok := data.(int8); ok {
+      return byte(b), true
+    }
+    if b, ok := data.(int16); ok {
+      return byte(b), true
+    }
+    if b, ok := data.(int32); ok {
+      return byte(b), true
+    }
+    if b, ok := data.(int64); ok {
+      return byte(b), true
+    }
+    if b, ok := data.(uint); ok {
+      return byte(b), true
+    }
+    if b, ok := data.(uint8); ok {
+      return byte(b), true
+    }
+    if b, ok := data.(uint16); ok {
+      return byte(b), true
+    }
+    if b, ok := data.(uint32); ok {
+      return byte(b), true
+    }
+    if b, ok := data.(uint64); ok {
+      return byte(b), true
+    }
+    if b, ok := data.(float32); ok {
+      return byte(int(b)), true
+    }
+    if b, ok := data.(float64); ok {
+      return byte(int(b)), true
+    }
+    if b, ok := data.(Stringer); ok {
+      data = b.String()
+    }
+    if b, ok := data.(string); ok {
+      i1, err := strconv.Atoi(b)
+      if err != nil {
+        return byte(int(i1)), true
+      }
+    }
+    return byte(0), false
+  case DOUBLE:
+    if b, ok := data.(float32); ok {
+      return float64(b), true
+    }
+    if b, ok := data.(float64); ok {
+      return b, true
+    }
+    if b, ok := data.(Numeric); ok {
+      return bool(b.Float64() != 0.0), true
+    }
+    if b, ok := data.(byte); ok {
+      return float64(b), true
+    }
+    if b, ok := data.(bool); ok {
+      if b {
+        return float64(1.0), true
+      }
+      return float64(0.0), true
+    }
+    if b, ok := data.(int); ok {
+      return float64(b), true
+    }
+    if b, ok := data.(int8); ok {
+      return float64(b), true
+    }
+    if b, ok := data.(int16); ok {
+      return float64(b), true
+    }
+    if b, ok := data.(int32); ok {
+      return float64(b), true
+    }
+    if b, ok := data.(int64); ok {
+      return float64(b), true
+    }
+    if b, ok := data.(uint); ok {
+      return float64(b), true
+    }
+    if b, ok := data.(uint8); ok {
+      return float64(b), true
+    }
+    if b, ok := data.(uint16); ok {
+      return float64(b), true
+    }
+    if b, ok := data.(uint32); ok {
+      return float64(b), true
+    }
+    if b, ok := data.(uint64); ok {
+      return float64(b), true
+    }
+    if b, ok := data.(Stringer); ok {
+      data = b.String()
+    }
+    if b, ok := data.(string); ok {
+      d1, err := strconv.Atof64(b)
+      if err != nil {
+        return d1, true
+      }
+    }
+    return float64(0), false
+  case I16:
+    if b, ok := data.(int16); ok {
+      return b, true
+    }
+    if b, ok := data.(int); ok {
+      return int16(b), true
+    }
+    if b, ok := data.(Numeric); ok {
+      return bool(b.Int16() != 0), true
+    }
+    if b, ok := data.(byte); ok {
+      return int16(b), true
+    }
+    if b, ok := data.(bool); ok {
+      if b {
+        return int16(1.0), true
+      }
+      return int16(0.0), true
+    }
+    if b, ok := data.(int8); ok {
+      return int16(b), true
+    }
+    if b, ok := data.(int32); ok {
+      return int16(b), true
+    }
+    if b, ok := data.(int64); ok {
+      return int16(b), true
+    }
+    if b, ok := data.(uint); ok {
+      return int16(b), true
+    }
+    if b, ok := data.(uint8); ok {
+      return int16(b), true
+    }
+    if b, ok := data.(uint16); ok {
+      return int16(b), true
+    }
+    if b, ok := data.(uint32); ok {
+      return int16(b), true
+    }
+    if b, ok := data.(uint64); ok {
+      return int16(b), true
+    }
+    if b, ok := data.(float32); ok {
+      return int16(int(b)), true
+    }
+    if b, ok := data.(float64); ok {
+      return int16(int(b)), true
+    }
+    if b, ok := data.(Stringer); ok {
+      data = b.String()
+    }
+    if b, ok := data.(string); ok {
+      i1, err := strconv.Atoi(b)
+      if err != nil {
+        return int16(i1), true
+      }
+    }
+    return int16(0), false
+  case I32:
+    if b, ok := data.(int32); ok {
+      return b, true
+    }
+    if b, ok := data.(int); ok {
+      return int32(b), true
+    }
+    if b, ok := data.(Numeric); ok {
+      return bool(b.Int32() != 0), true
+    }
+    if b, ok := data.(byte); ok {
+      return int32(b), true
+    }
+    if b, ok := data.(bool); ok {
+      if b {
+        return int32(1.0), true
+      }
+      return int32(0.0), true
+    }
+    if b, ok := data.(int8); ok {
+      return int32(b), true
+    }
+    if b, ok := data.(int16); ok {
+      return int32(b), true
+    }
+    if b, ok := data.(int64); ok {
+      return int32(b), true
+    }
+    if b, ok := data.(uint); ok {
+      return int32(b), true
+    }
+    if b, ok := data.(uint8); ok {
+      return int32(b), true
+    }
+    if b, ok := data.(uint16); ok {
+      return int32(b), true
+    }
+    if b, ok := data.(uint32); ok {
+      return int32(b), true
+    }
+    if b, ok := data.(uint64); ok {
+      return int32(b), true
+    }
+    if b, ok := data.(float32); ok {
+      return int32(int(b)), true
+    }
+    if b, ok := data.(float64); ok {
+      return int32(int(b)), true
+    }
+    if b, ok := data.(Stringer); ok {
+      data = b.String()
+    }
+    if b, ok := data.(string); ok {
+      i1, err := strconv.Atoi(b)
+      if err != nil {
+        return int32(i1), true
+      }
+    }
+    return int32(0), false
+  case I64:
+    if b, ok := data.(int64); ok {
+      return b, true
+    }
+    if b, ok := data.(int32); ok {
+      return int64(b), true
+    }
+    if b, ok := data.(int); ok {
+      return int64(b), true
+    }
+    if b, ok := data.(Numeric); ok {
+      return bool(b.Int64() != 0), true
+    }
+    if b, ok := data.(byte); ok {
+      return int64(b), true
+    }
+    if b, ok := data.(bool); ok {
+      if b {
+        return int64(1.0), true
+      }
+      return int64(0.0), true
+    }
+    if b, ok := data.(int8); ok {
+      return int64(b), true
+    }
+    if b, ok := data.(int16); ok {
+      return int64(b), true
+    }
+    if b, ok := data.(uint); ok {
+      return int64(b), true
+    }
+    if b, ok := data.(uint8); ok {
+      return int64(b), true
+    }
+    if b, ok := data.(uint16); ok {
+      return int64(b), true
+    }
+    if b, ok := data.(uint32); ok {
+      return int64(b), true
+    }
+    if b, ok := data.(uint64); ok {
+      return int64(b), true
+    }
+    if b, ok := data.(float32); ok {
+      return int64(b), true
+    }
+    if b, ok := data.(float64); ok {
+      return int64(b), true
+    }
+    if b, ok := data.(Stringer); ok {
+      data = b.String()
+    }
+    if b, ok := data.(string); ok {
+      i1, err := strconv.Atoi64(b)
+      if err != nil {
+        return i1, true
+      }
+    }
+    return int64(0), false
+  case STRING, UTF8, UTF16:
+    if b, ok := data.(Enumer); ok {
+      if i1, ok := data.(int); ok {
+        return i1, true
+      }
+      return b.String(), true
+    }
+    if b, ok := data.(Stringer); ok {
+      return b.String(), true
+    }
+    if b, ok := data.(string); ok {
+      return b, true
+    }
+    if b, ok := data.(int); ok {
+      return string(b), true
+    }
+    if b, ok := data.(byte); ok {
+      return string(b), true
+    }
+    if b, ok := data.(bool); ok {
+      if b {
+        return "true", true
+      }
+      return "false", true
+    }
+    if b, ok := data.(int8); ok {
+      return string(b), true
+    }
+    if b, ok := data.(int16); ok {
+      return string(b), true
+    }
+    if b, ok := data.(int32); ok {
+      return string(b), true
+    }
+    if b, ok := data.(int64); ok {
+      return string(b), true
+    }
+    if b, ok := data.(uint); ok {
+      return string(b), true
+    }
+    if b, ok := data.(uint8); ok {
+      return string(b), true
+    }
+    if b, ok := data.(uint16); ok {
+      return string(b), true
+    }
+    if b, ok := data.(uint32); ok {
+      return string(b), true
+    }
+    if b, ok := data.(uint64); ok {
+      return string(b), true
+    }
+    if b, ok := data.(float32); ok {
+      return strconv.Ftoa32(b, 'g', -1), true
+    }
+    if b, ok := data.(float64); ok {
+      return strconv.Ftoa64(b, 'g', -1), true
+    }
+    return "", false
+  case STRUCT:
+    if b, ok := data.(TStruct); ok {
+      return b, true
+    }
+    return NewTStructEmpty(""), true
+  case MAP:
+    if b, ok := data.(TMap); ok {
+      return b, true
+    }
+    return NewTMapDefault(), false
+  case LIST:
+    if b, ok := data.(TList); ok {
+      return b, true
+    }
+    return NewTListDefault(), false
+  case SET:
+    if b, ok := data.(TSet); ok {
+      return b, true
+    }
+    return NewTSetDefault(), false
+  default:
+    panic("Invalid thrift type to coerce")
+  }
+  return nil, false
+}
+
+type EqualsOtherInterface interface {
+  Equals(other interface{}) bool
+}
+
+type EqualsMap interface {
+  Equals(other TMap) bool
+}
+
+type EqualsSet interface {
+  Equals(other TSet) bool
+}
+
+type EqualsList interface {
+  Equals(other TList) bool
+}
+
+type EqualsStruct interface {
+  Equals(other TStruct) bool
+}
diff --git a/test/ThriftTest.thrift b/test/ThriftTest.thrift
index 237023b..83e4e39 100644
--- a/test/ThriftTest.thrift
+++ b/test/ThriftTest.thrift
@@ -31,6 +31,7 @@
 namespace st ThriftTest
 namespace py ThriftTest
 namespace py.twisted ThriftTest
+namespace go ThriftTest
 namespace * thrift.test
 
 /**
diff --git a/tutorial/go/Make.deps b/tutorial/go/Make.deps
new file mode 100644
index 0000000..e4c2b20
--- /dev/null
+++ b/tutorial/go/Make.deps
@@ -0,0 +1,135 @@
+src.install: fmt.install net.install os.install strconv.install thrift.install
+archive/tar.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/archive/tar.a
+archive/zip.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/archive/zip.a
+asn1.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/asn1.a
+big.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/big.a
+bufio.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/bufio.a
+bytes.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/bytes.a
+cmath.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/cmath.a
+compress/flate.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/compress/flate.a
+compress/gzip.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/compress/gzip.a
+compress/zlib.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/compress/zlib.a
+container/heap.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/container/heap.a
+container/list.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/container/list.a
+container/ring.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/container/ring.a
+container/vector.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/container/vector.a
+crypto.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto.a
+crypto/aes.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/aes.a
+crypto/block.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/block.a
+crypto/blowfish.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/blowfish.a
+crypto/cast5.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/cast5.a
+crypto/cipher.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/cipher.a
+crypto/dsa.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/dsa.a
+crypto/elliptic.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/elliptic.a
+crypto/hmac.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/hmac.a
+crypto/md4.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/md4.a
+crypto/md5.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/md5.a
+crypto/ocsp.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/ocsp.a
+crypto/rand.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/rand.a
+crypto/rc4.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/rc4.a
+crypto/ripemd160.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/ripemd160.a
+crypto/rsa.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/rsa.a
+crypto/sha1.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/sha1.a
+crypto/sha256.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/sha256.a
+crypto/sha512.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/sha512.a
+crypto/subtle.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/subtle.a
+crypto/tls.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/tls.a
+crypto/twofish.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/twofish.a
+crypto/x509.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/x509.a
+crypto/xtea.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/crypto/xtea.a
+debug/dwarf.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/debug/dwarf.a
+debug/macho.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/debug/macho.a
+debug/elf.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/debug/elf.a
+debug/gosym.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/debug/gosym.a
+debug/pe.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/debug/pe.a
+debug/proc.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/debug/proc.a
+ebnf.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/ebnf.a
+encoding/ascii85.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/encoding/ascii85.a
+encoding/base32.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/encoding/base32.a
+encoding/base64.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/encoding/base64.a
+encoding/binary.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/encoding/binary.a
+encoding/git85.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/encoding/git85.a
+encoding/hex.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/encoding/hex.a
+encoding/line.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/encoding/line.a
+encoding/pem.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/encoding/pem.a
+exec.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/exec.a
+exp/datafmt.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/exp/datafmt.a
+exp/draw.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/exp/draw.a
+exp/draw/x11.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/exp/draw/x11.a
+exp/eval.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/exp/eval.a
+expvar.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/expvar.a
+flag.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/flag.a
+fmt.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/fmt.a
+go/ast.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/go/ast.a
+go/doc.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/go/doc.a
+go/parser.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/go/parser.a
+go/printer.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/go/printer.a
+go/scanner.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/go/scanner.a
+go/token.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/go/token.a
+go/typechecker.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/go/typechecker.a
+gob.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/gob.a
+hash.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/hash.a
+hash/adler32.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/hash/adler32.a
+hash/crc32.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/hash/crc32.a
+hash/crc64.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/hash/crc64.a
+html.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/html.a
+http.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/http.a
+http/pprof.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/http/pprof.a
+image.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/image.a
+image/jpeg.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/image/jpeg.a
+image/png.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/image/png.a
+index/suffixarray.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/index/suffixarray.a
+io.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/io.a
+io/ioutil.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/io/ioutil.a
+json.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/json.a
+log.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/log.a
+math.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/math.a
+mime.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/mime.a
+mime/multipart.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/mime/multipart.a
+net.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/net.a
+net/dict.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/net/dict.a
+net/textproto.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/net/textproto.a
+netchan.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/netchan.a
+os.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/os.a
+os/signal.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/os/signal.a
+patch.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/patch.a
+path.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/path.a
+rand.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/rand.a
+reflect.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/reflect.a
+regexp.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/regexp.a
+rpc.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/rpc.a
+rpc/jsonrpc.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/rpc/jsonrpc.a
+runtime.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/runtime.a
+runtime/cgo.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/runtime/cgo.a
+runtime/debug.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/runtime/debug.a
+runtime/pprof.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/runtime/pprof.a
+scanner.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/scanner.a
+smtp.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/smtp.a
+sort.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/sort.a
+strconv.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/strconv.a
+strings.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/strings.a
+sync.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/sync.a
+syscall.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/syscall.a
+syslog.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/syslog.a
+tabwriter.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/tabwriter.a
+template.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/template.a
+testing.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/testing.a
+testing/iotest.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/testing/iotest.a
+testing/quick.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/testing/quick.a
+testing/script.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/testing/script.a
+time.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/time.a
+try.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/try.a
+unicode.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/unicode.a
+utf16.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/utf16.a
+utf8.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/utf8.a
+websocket.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/websocket.a
+xml.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/xml.a
+../cmd/cgo.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/../cmd/cgo.a
+../cmd/ebnflint.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/../cmd/ebnflint.a
+../cmd/godoc.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/../cmd/godoc.a
+../cmd/gofmt.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/../cmd/gofmt.a
+../cmd/goinstall.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/../cmd/goinstall.a
+../cmd/govet.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/../cmd/govet.a
+../cmd/goyacc.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/../cmd/goyacc.a
+../cmd/hgpatch.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/../cmd/hgpatch.a
+thrift.install: ${GOROOT}/pkg/${GOOS}_${GOARCH}/thrift.a
diff --git a/tutorial/go/Makefile b/tutorial/go/Makefile
new file mode 100644
index 0000000..50c5dfe
--- /dev/null
+++ b/tutorial/go/Makefile
@@ -0,0 +1,44 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include $(GOROOT)/src/Make.inc
+
+all: Make.deps install
+
+TARG=thriftlib/tutorialcalculator
+
+DIRS=\
+  src/\
+
+GOFILES=\
+
+
+clean.dirs: $(addsuffix .clean, $(DIRS))
+install.dirs: $(addsuffix .install, $(DIRS))
+test.dirs: $(addsuffix .test, $(DIRS))
+
+
+%.clean:
+	+cd $* && $(MAKE) clean
+
+%.install:
+	+cd $* && $(MAKE) install
+
+%.test:
+	+cd $* && $(MAKE) test
+
+
+
+Make.deps:
+	./deps.bash
+
+deps:
+	./deps.bash
+
+clean: clean.dirs
+
+install: install.dirs
+
+test:	test.dirs
+
diff --git a/tutorial/go/deps.bash b/tutorial/go/deps.bash
new file mode 100644
index 0000000..aec6ec2
--- /dev/null
+++ b/tutorial/go/deps.bash
@@ -0,0 +1,45 @@
+#!/usr/bin/env bash
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+OUT="Make.deps"
+TMP="Make.deps.tmp"
+
+if [ -f $OUT ] && ! [ -w $OUT ]; then
+	echo "$0: $OUT is read-only; aborting." 1>&2
+	exit 1
+fi
+
+# Get list of directories from Makefile
+dirs=$(sed '1,/^DIRS=/d; /^$/,$d; s/\\//g' Makefile)
+dirs2=$(sed '1,/^DIRS=/d; /^$/,$d; s/\\//g' $GOROOT/src/pkg/Makefile)
+dirs3="thrift"
+dirpat=$(echo $dirs $dirs2 $dirs3 | sed 's/ /|/g; s/.*/^(&)$/')
+
+for dir in $dirs; do (
+	cd $dir || exit 1
+
+	sources=$(sed -n 's/\.go\\/.go/p' Makefile)
+	sources=$(ls $sources 2> /dev/null)  # remove .s, .c, etc.
+
+	deps=$(
+		sed -n '/^import.*"/p; /^import[ \t]*(/,/^)/p' $sources /dev/null |
+		cut -d '"' -f2 |
+		egrep "$dirpat" |
+		grep -v "^$dir\$" |
+		sed 's/$/.install/' |
+		sort -u
+	)
+
+	echo $dir.install: $deps
+) done > $TMP
+
+for dir in $dirs2; do (
+  echo $dir.install: \${GOROOT}/pkg/\${GOOS}_\${GOARCH}/${dir}.a
+) done >> $TMP
+for dir in $dirs3; do (
+  echo $dir.install: \${GOROOT}/pkg/\${GOOS}_\${GOARCH}/${dir}.a
+) done >> $TMP
+
+mv $TMP $OUT
diff --git a/tutorial/go/src/CalculatorHandler.go b/tutorial/go/src/CalculatorHandler.go
new file mode 100644
index 0000000..9eb2838
--- /dev/null
+++ b/tutorial/go/src/CalculatorHandler.go
@@ -0,0 +1,101 @@
+package main;
+
+/*
+ * 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.
+ */
+
+import (
+  "fmt"
+  "os"
+  "strconv"
+  "thriftlib/tutorial"
+  "thriftlib/shared"
+)
+
+type CalculatorHandler struct {
+  log map[int]*shared.SharedStruct
+}
+
+func NewCalculatorHandler() *CalculatorHandler {
+  return &CalculatorHandler{log:make(map[int]*shared.SharedStruct)}
+}
+
+func (p *CalculatorHandler) Ping() (err os.Error) {
+  fmt.Print("ping()\n")
+  return nil
+}
+
+func (p *CalculatorHandler) Add(num1 int32, num2 int32) (retval17 int32, err os.Error) {
+  fmt.Print("add(", num1, ",", num2, ")\n")
+  return num1 + num2, nil
+}
+
+func (p *CalculatorHandler) Calculate(logid int32, w *tutorial.Work) (val int32, ouch *tutorial.InvalidOperation, err os.Error) {
+  fmt.Print("calculate(", logid, ", {", w.Op, ",", w.Num1, ",", w.Num2, "})\n")
+  switch(w.Op) {
+  case tutorial.ADD:
+    val = w.Num1 + w.Num2
+    break
+  case tutorial.SUBTRACT:
+    val = w.Num1 - w.Num2
+    break
+  case tutorial.MULTIPLY:
+    val = w.Num1 * w.Num2
+    break
+  case tutorial.DIVIDE:
+    if w.Num2 == 0 {
+      ouch = tutorial.NewInvalidOperation()
+      ouch.What = int32(w.Op)
+      ouch.Why = "Cannot divide by 0"
+      return
+    }
+    val = w.Num1 / w.Num2
+    break
+  default:
+    ouch = tutorial.NewInvalidOperation()
+    ouch.What = int32(w.Op)
+    ouch.Why = "Unknown operation"
+    return
+  }
+  entry := shared.NewSharedStruct()
+  entry.Key = logid
+  entry.Value = strconv.Itoa(int(val))
+  k := int(logid)
+  /*
+  oldvalue, exists := p.log[k]
+  if exists {
+    fmt.Print("Replacing ", oldvalue, " with ", entry, " for key ", k, "\n")
+  } else {
+    fmt.Print("Adding ", entry, " for key ", k, "\n")
+  }
+  */
+  p.log[k] = entry, true
+  return val, ouch, err
+}
+
+func (p *CalculatorHandler) GetStruct(key int32) (*shared.SharedStruct, os.Error) {
+  fmt.Print("getStruct(", key, ")\n")
+  v, _ := p.log[int(key)]
+  return v, nil
+}
+
+func (p *CalculatorHandler) Zip() (err os.Error) {
+  fmt.Print("zip()\n")
+  return nil
+}
+
diff --git a/tutorial/go/src/GoClient.go b/tutorial/go/src/GoClient.go
new file mode 100644
index 0000000..9440530
--- /dev/null
+++ b/tutorial/go/src/GoClient.go
@@ -0,0 +1,92 @@
+package main;
+
+
+/*
+ * 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.
+ */
+
+
+import (
+  "fmt"
+  "net"
+  "os"
+  "thrift"
+  "thriftlib/tutorial"
+)
+
+func Perform(client *tutorial.CalculatorClient) (err os.Error) {
+  client.Ping()
+  fmt.Print("ping()\n")
+  
+  sum, _ := client.Add(1, 1)
+  fmt.Print("1+1=", sum, "\n")
+  
+  work := tutorial.NewWork()
+  work.Op = tutorial.DIVIDE
+  work.Num1 = 1
+  work.Num2 = 0
+  quotient, ouch, err := client.Calculate(1, work)
+  if err != nil {
+    fmt.Print("Error during operation: ", err.String(), "\n")
+    return err
+  } else if ouch != nil {
+    fmt.Print("Invalid operation: ", ouch.String(), "\n")
+  } else {
+    fmt.Print("Whoa we can divide by 0 with new value: ", quotient, "\n")
+  }
+  
+  work.Op = tutorial.SUBTRACT
+  work.Num1 = 15
+  work.Num2 = 10
+  diff, ouch, err := client.Calculate(1, work)
+  if err != nil {
+    fmt.Print("Error during operation: ", err.String(), "\n")
+    return err
+  } else if ouch != nil {
+    fmt.Print("Invalid operation: ", ouch.String(), "\n")
+  } else {
+    fmt.Print("15-10=", diff, "\n")
+  }
+  
+  log, err := client.GetStruct(1)
+  if err != nil {
+    fmt.Print("Unable to get struct: ", err.String(), "\n")
+    return err
+  } else {
+    fmt.Print("Check log: ", log.Value, "\n")
+  }
+  return err
+}
+
+
+func RunClient(transportFactory thrift.TTransportFactory, protocolFactory thrift.TProtocolFactory) os.Error {
+  addr, err := net.ResolveTCPAddr("localhost:9090")
+  if err != nil {
+    fmt.Print("Error resolving address: ", err.String(), "\n")
+    return err
+  }
+  transport := thrift.NewTSocketAddr(addr)
+  if err = transport.Open(); err != nil {
+    fmt.Print("Error opening connection for protocol ", addr.Network(), " to ", addr.String(), ": ", err.String(), "\n")
+    return err
+  }
+  useTransport := transportFactory.GetTransport(transport)
+  client := tutorial.NewCalculatorClientFactory(useTransport, protocolFactory)
+  Perform(client)
+  return transport.Close()
+}
diff --git a/tutorial/go/src/GoServer.go b/tutorial/go/src/GoServer.go
new file mode 100644
index 0000000..f70a2a9
--- /dev/null
+++ b/tutorial/go/src/GoServer.go
@@ -0,0 +1,85 @@
+package main;
+
+
+/*
+ * 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.
+ */
+
+
+import (
+  "fmt"
+  "net"
+  "thrift"
+  "thriftlib/tutorial"
+)
+
+
+type GoServer struct {
+  handler tutorial.ICalculator
+  processor *tutorial.CalculatorProcessor
+}
+
+func NewGoServer() *GoServer {
+  handler := NewCalculatorHandler()
+  processor := tutorial.NewCalculatorProcessor(handler)
+  return &GoServer{handler:handler, processor:processor}
+}
+
+func Simple(processor *tutorial.CalculatorProcessor, transportFactory thrift.TTransportFactory, protocolFactory thrift.TProtocolFactory, ch chan int) {
+  addr, err := net.ResolveTCPAddr("localhost:9090")
+  if err != nil {
+    fmt.Print("Error resolving address: ", err.String(), "\n")
+    return
+  }
+  serverTransport, err := thrift.NewTServerSocketAddr(addr)
+  if err != nil {
+    fmt.Print("Error creating server socket: ", err.String(), "\n")
+    return
+  }
+  server := thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory)
+  // Use this for a multithreaded server
+  // TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor));
+  
+  fmt.Print("Starting the simple server... on ", addr, "\n")
+  for {
+    err = server.Serve()
+    if err != nil {
+      fmt.Print("Error during simple server: ", err.String(), "\n")
+      return
+    }
+  }
+  fmt.Print("Done with the simple server\n")
+  ch <- 1
+}
+
+func Secure(processor *tutorial.CalculatorProcessor) {
+  addr, _ := net.ResolveTCPAddr("localhost:9091")
+  serverTransport, _ := thrift.NewTNonblockingServerSocketAddr(addr)
+  server := thrift.NewTSimpleServer2(processor, serverTransport)
+  fmt.Print("Starting the secure server... on ", addr, "\n")
+  server.Serve()
+  fmt.Print("Done with the secure server\n")
+}
+
+func RunServer(transportFactory thrift.TTransportFactory, protocolFactory thrift.TProtocolFactory) {
+  server := NewGoServer()
+  ch := make(chan int)
+  go Simple(server.processor, transportFactory, protocolFactory, ch)
+  //go Secure(server.processor)
+  _ = <- ch
+}
diff --git a/tutorial/go/src/Makefile b/tutorial/go/src/Makefile
new file mode 100644
index 0000000..87acbca
--- /dev/null
+++ b/tutorial/go/src/Makefile
@@ -0,0 +1,22 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include $(GOROOT)/src/Make.inc
+
+all: install
+
+TARG=TutorialServerClient
+
+DIRS=\
+
+GOFILES=\
+  CalculatorHandler.go\
+  GoClient.go\
+  GoServer.go\
+  main.go
+
+-include ../Make.deps
+
+include $(GOROOT)/src/Make.cmd
+
diff --git a/tutorial/go/src/main.go b/tutorial/go/src/main.go
new file mode 100644
index 0000000..30b5d52
--- /dev/null
+++ b/tutorial/go/src/main.go
@@ -0,0 +1,86 @@
+package main;
+
+
+/*
+ * 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.
+ */
+
+
+import (
+  "flag"
+  "fmt"
+  "os"
+  "thrift"
+)
+
+func Usage() {
+  fmt.Fprint(os.Stderr, "Usage of ", os.Args[0], " <--server | --client>:\n")
+  flag.PrintDefaults()
+  fmt.Fprint(os.Stderr, "\n")
+  os.Exit(0)
+}
+
+func main() {
+  flag.Usage = Usage
+  var client bool
+  var server bool
+  var protocol string
+  var framed bool
+  var useHttp bool
+  var help bool
+  
+  flag.BoolVar(&client, "client", false, "Run client")
+  flag.BoolVar(&server, "server", false, "Run server")
+  flag.StringVar(&protocol, "P", "binary", "Specify the protocol (binary, compact, simplejson)")
+  flag.BoolVar(&framed, "framed", false, "Use framed transport")
+  flag.BoolVar(&useHttp, "http", false, "Use http")
+  flag.BoolVar(&help, "help", false, "See usage string")
+  flag.Parse()
+  if help || (client && server) || !(client || server) {
+    fmt.Print("flag.NArg() == ", flag.NArg(), "\n")
+    flag.Usage()
+  }
+  var protocolFactory thrift.TProtocolFactory
+  switch protocol {
+  case "compact":
+    protocolFactory = thrift.NewTCompactProtocolFactory()
+  case "simplejson":
+    protocolFactory = thrift.NewTSimpleJSONProtocolFactory()
+  case "json":
+    protocolFactory = thrift.NewTJSONProtocolFactory()
+  case "binary", "":
+    protocolFactory = thrift.NewTBinaryProtocolFactoryDefault()
+  default:
+    fmt.Fprint(os.Stderr, "Invalid protocol specified", protocol, "\n")
+    Usage()
+    os.Exit(1)
+  }
+  transportFactory := thrift.NewTTransportFactory()
+  if framed {
+    transportFactory = thrift.NewTFramedTransportFactory(transportFactory)
+  }
+  
+  if(client) {
+    RunClient(transportFactory, protocolFactory)
+  } else if(server) {
+    RunServer(transportFactory, protocolFactory)
+  } else {
+    flag.Usage()
+  }
+  os.Exit(0)
+}